Table.indexes and Table.xindexes build their PRAGMA statements with naive f-string quoting instead of quote_identifier(), so any identifier containing a double quote produces malformed SQL:
import sqlite_utils
db = sqlite_utils.Database(memory=True)
db['Go"sh'].insert({"id": 1, 'c"1': 2}, pk="id")
db['Go"sh'].create_index(['c"1'])
db['Go"sh'].indexes
# sqlite3.OperationalError: near "sh": syntax error
The four sites are in sqlite_utils/db.py:
indexes / xindexes: sql = f'PRAGMA index_list("{self.name}")' — embedded " in the table name is never doubled
- both properties then wrap the index name with an ad-hoc heuristic (
f'"{index_name}"' if not index_name.startswith('"') else index_name) that has the same flaw
This looks like a missed spot in the #678 migration (fb93452, "Use double quotes not braces for tables and columns"): quote_identifier() is used 103 times in the same file, including the neighbouring PRAGMA table_info and PRAGMA foreign_key_list, but these four sites kept the old quoting.
It cascades beyond introspection because self.indexes is consumed by transform(), drop_index() and Database.create, so transform() raises OperationalError for any table whose name contains a " — or any table carrying an index on a column whose name contains one. Column names like that routinely arrive from CSV/JSON headers.
Related (same family, different method, can file separately if useful): detect_fts() interpolates content="{self.name}" into its like2 pattern without doubling embedded quotes, so search() reports "Full-text search is not configured" immediately after a successful enable_fts() on such a table.
I have a fix ready (replace the four sites with quote_identifier(), net −6 lines, plus two regression tests) and will open a PR referencing this issue.
Table.indexesandTable.xindexesbuild their PRAGMA statements with naive f-string quoting instead ofquote_identifier(), so any identifier containing a double quote produces malformed SQL:The four sites are in
sqlite_utils/db.py:indexes/xindexes:sql = f'PRAGMA index_list("{self.name}")'— embedded"in the table name is never doubledf'"{index_name}"' if not index_name.startswith('"') else index_name) that has the same flawThis looks like a missed spot in the #678 migration (fb93452, "Use double quotes not braces for tables and columns"):
quote_identifier()is used 103 times in the same file, including the neighbouringPRAGMA table_infoandPRAGMA foreign_key_list, but these four sites kept the old quoting.It cascades beyond introspection because
self.indexesis consumed bytransform(),drop_index()andDatabase.create, sotransform()raisesOperationalErrorfor any table whose name contains a"— or any table carrying an index on a column whose name contains one. Column names like that routinely arrive from CSV/JSON headers.Related (same family, different method, can file separately if useful):
detect_fts()interpolatescontent="{self.name}"into itslike2pattern without doubling embedded quotes, sosearch()reports "Full-text search is not configured" immediately after a successfulenable_fts()on such a table.I have a fix ready (replace the four sites with
quote_identifier(), net −6 lines, plus two regression tests) and will open a PR referencing this issue.