From e6be6267a4eda2d35e57a50400208fe1bb66d6d3 Mon Sep 17 00:00:00 2001 From: nyxst4ck Date: Wed, 12 Aug 2026 18:15:17 -0300 Subject: [PATCH] Use quote_identifier() in indexes/xindexes PRAGMA statements (#825) Closes #824 --- sqlite_utils/db.py | 14 ++++---------- tests/test_introspect.py | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 66dc700..a59597b 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -2375,14 +2375,11 @@ class Table(Queryable): @property def indexes(self) -> list[Index]: "List of indexes defined on this table." - sql = f'PRAGMA index_list("{self.name}")' + sql = f"PRAGMA index_list({quote_identifier(self.name)})" indexes = [] for row in self.db.execute_returning_dicts(sql): index_name = row["name"] - index_name_quoted = ( - f'"{index_name}"' if not index_name.startswith('"') else index_name - ) - column_sql = f"PRAGMA index_info({index_name_quoted})" + column_sql = f"PRAGMA index_info({quote_identifier(index_name)})" columns = [] for seqno, cid, name in self.db.execute(column_sql).fetchall(): columns.append(name) @@ -2397,14 +2394,11 @@ class Table(Queryable): @property def xindexes(self) -> list[XIndex]: "List of indexes defined on this table using the more detailed ``XIndex`` format." - sql = f'PRAGMA index_list("{self.name}")' + sql = f"PRAGMA index_list({quote_identifier(self.name)})" indexes = [] for row in self.db.execute_returning_dicts(sql): index_name = row["name"] - index_name_quoted = ( - f'"{index_name}"' if not index_name.startswith('"') else index_name - ) - column_sql = f"PRAGMA index_xinfo({index_name_quoted})" + column_sql = f"PRAGMA index_xinfo({quote_identifier(index_name)})" index_columns = [] for info in self.db.execute(column_sql).fetchall(): index_columns.append(XIndexColumn(*info)) diff --git a/tests/test_introspect.py b/tests/test_introspect.py index b0953f1..03b02cc 100644 --- a/tests/test_introspect.py +++ b/tests/test_introspect.py @@ -161,6 +161,31 @@ def test_xindexes(fresh_db): ] +def test_indexes_with_double_quotes_in_identifiers(fresh_db): + fresh_db['Go"sh'].insert({"id": 1, 'c"1': 2}, pk="id") + fresh_db['Go"sh'].create_index(['c"1']) + assert [(index.name, index.columns) for index in fresh_db['Go"sh'].indexes] == [ + ('idx_Go"sh_c"1', ['c"1']) + ] + assert fresh_db['Go"sh'].xindexes == [ + XIndex( + name='idx_Go"sh_c"1', + columns=[ + XIndexColumn(seqno=0, cid=1, name='c"1', desc=0, coll="BINARY", key=1), + XIndexColumn(seqno=1, cid=-1, name=None, desc=0, coll="BINARY", key=0), + ], + ) + ] + + +def test_transform_table_with_double_quotes_in_identifiers(fresh_db): + fresh_db['Go"sh'].insert({"id": 1, 'c"1': 2, "c2": 3}, pk="id") + fresh_db['Go"sh'].create_index(['c"1']) + fresh_db['Go"sh'].transform(types={"c2": str}) + assert fresh_db['Go"sh'].columns_dict["c2"] is str + assert [index.columns for index in fresh_db['Go"sh'].indexes] == [['c"1']] + + @pytest.mark.parametrize( "column,expected_table_guess", (