From 5752491154ad19e29abec8d69fa4076d996d964e Mon Sep 17 00:00:00 2001 From: John A Stevenson Date: Mon, 19 Aug 2024 17:59:36 +0100 Subject: [PATCH] Update SQLite unique constraint parser to handle tabs Fixes: #11746 Sometimes the whitespace between fields in a column definition in SQLite can be tabs instead of spaces, particularly between the column name and the type definition. This commit updates the regular expression used to detect UNIQUE constraints so that it handles this situation. --- lib/sqlalchemy/dialects/sqlite/base.py | 4 ++-- test/dialect/test_sqlite.py | 27 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index a678e10940..cf8f16966b 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -2588,8 +2588,8 @@ class SQLiteDialect(default.DefaultDialect): return UNIQUE_PATTERN = r'(?:CONSTRAINT "?(.+?)"? +)?UNIQUE *\((.+?)\)' INLINE_UNIQUE_PATTERN = ( - r'(?:(".+?")|(?:[\[`])?([a-z0-9_]+)(?:[\]`])?) ' - r"+[a-z0-9_ ]+? +UNIQUE" + r'(?:(".+?")|(?:[\[`])?([a-z0-9_]+)(?:[\]`])?)[\t ]' + r"+[a-z0-9_ ]+?[\t ]+UNIQUE" ) for match in re.finditer(UNIQUE_PATTERN, table_data, re.I): diff --git a/test/dialect/test_sqlite.py b/test/dialect/test_sqlite.py index b137c0579f..8afa800530 100644 --- a/test/dialect/test_sqlite.py +++ b/test/dialect/test_sqlite.py @@ -2503,17 +2503,27 @@ class ConstraintReflectionTest(fixtures.TestBase): argnames="colname,expected", ) @testing.combinations( - "uq", "uq_inline", "pk", "ix", argnames="constraint_type" + "uq", + "uq_inline", + "uq_inline_tab_before", # tab before column params + "uq_inline_tab_within", # tab within column params + "pk", + "ix", + argnames="constraint_type", ) def test_constraint_cols( self, colname, expected, constraint_type, connection, metadata ): - if constraint_type == "uq_inline": + if constraint_type.startswith("uq_inline"): + inline_create_sql = { + "uq_inline": "CREATE TABLE t (%s INTEGER UNIQUE)", + "uq_inline_tab_before": "CREATE TABLE t (%s\tINTEGER UNIQUE)", + "uq_inline_tab_within": "CREATE TABLE t (%s INTEGER\tUNIQUE)", + } + t = Table("t", metadata, Column(colname, Integer)) connection.exec_driver_sql( - """ - CREATE TABLE t (%s INTEGER UNIQUE) - """ + inline_create_sql[constraint_type] % connection.dialect.identifier_preparer.quote(colname) ) else: @@ -2531,7 +2541,12 @@ class ConstraintReflectionTest(fixtures.TestBase): t.create(connection) - if constraint_type in ("uq", "uq_inline"): + if constraint_type in ( + "uq", + "uq_inline", + "uq_inline_tab_before", + "uq_inline_tab_within", + ): const = inspect(connection).get_unique_constraints("t")[0] eq_(const["column_names"], [expected]) elif constraint_type == "pk": -- 2.47.2