]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
More adjustment to this SQLite related issue which was released in
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 14 Dec 2012 15:29:46 +0000 (10:29 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 14 Dec 2012 15:29:46 +0000 (10:29 -0500)
0.7.9, to intercept legacy SQLite quoting characters when reflecting
foreign keys.  In addition to intercepting double quotes, other
quoting characters such as brackets, backticks, and single quotes
are now also intercepted. [ticket:2568]

doc/build/changelog/changelog_07.rst
doc/build/changelog/changelog_08.rst
lib/sqlalchemy/dialects/sqlite/base.py
test/dialect/test_sqlite.py

index d8e4e06cec7a7f7cdea2212dadcc437597bb53af..c778fb84b9d38cc227d8f0ae181ff8e2a4e62bd4 100644 (file)
@@ -8,6 +8,16 @@
     :version: 0.7.10
     :released:
 
+    .. change::
+        :tags: sqlite, bug
+        :tickets: 2568
+
+      More adjustment to this SQLite related issue which was released in
+      0.7.9, to intercept legacy SQLite quoting characters when reflecting
+      foreign keys.  In addition to intercepting double quotes, other
+      quoting characters such as brackets, backticks, and single quotes
+      are now also intercepted.
+
     .. change::
         :tags: sql, bug
         :tickets: 2631
index 61b7a5cc463c3aff2c5e6747c1b24a79478693a6..3b83cdb234d9efcec37899940691794d69c3f6e9 100644 (file)
@@ -6,6 +6,16 @@
 .. changelog::
     :version: 0.8.0b2
 
+    .. change::
+        :tags: sqlite, bug
+        :tickets: 2568
+
+      More adjustment to this SQLite related issue which was released in
+      0.7.9, to intercept legacy SQLite quoting characters when reflecting
+      foreign keys.  In addition to intercepting double quotes, other
+      quoting characters such as brackets, backticks, and single quotes
+      are now also intercepted.  Also in 0.7.10.
+
     .. change::
         :tags: orm, bug
         :tickets: 2635
index f1be0385dd78cd0d2b42b0e4cafc728b9918052f..cd462021f7f4fbda0e150e184c2c60b1f8000a29 100644 (file)
@@ -616,6 +616,8 @@ class SQLiteDialect(default.DefaultDialect):
     supports_cast = True
     supports_default_values = True
 
+    _broken_fk_pragma_quotes = False
+
     def __init__(self, isolation_level=None, native_datetime=False, **kwargs):
         default.DefaultDialect.__init__(self, **kwargs)
         self.isolation_level = isolation_level
@@ -635,6 +637,12 @@ class SQLiteDialect(default.DefaultDialect):
                                 self.dbapi.sqlite_version_info >= (3, 7, 11)
                                 #  http://www.sqlite.org/releaselog/3_7_11.html
 
+            # see http://www.sqlalchemy.org/trac/ticket/2568
+            # as well as http://www.sqlite.org/src/info/600482d161
+            self._broken_fk_pragma_quotes = \
+                                self.dbapi.sqlite_version_info < (3, 6, 14)
+
+
     _isolation_lookup = {
         'READ UNCOMMITTED': 1,
         'SERIALIZABLE': 0
@@ -851,37 +859,40 @@ class SQLiteDialect(default.DefaultDialect):
             if row is None:
                 break
             (numerical_id, rtbl, lcol, rcol) = (row[0], row[2], row[3], row[4])
-            # sqlite won't return rcol if the table
-            # was created with REFERENCES <tablename>, no col
-            if rcol is None:
-                rcol = lcol
-
-            # see http://www.sqlalchemy.org/trac/ticket/2568
-            # as well as http://www.sqlite.org/src/info/600482d161
-            if self.dbapi.sqlite_version_info < (3, 6, 14):
-                rtbl = re.sub(r'^\"|\"$', '', rtbl)
 
-            try:
-                fk = fks[numerical_id]
-            except KeyError:
-                fk = {
-                    'name': None,
-                    'constrained_columns': [],
-                    'referred_schema': None,
-                    'referred_table': rtbl,
-                    'referred_columns': []
-                }
-                fkeys.append(fk)
-                fks[numerical_id] = fk
-
-            # look up the table based on the given table's engine, not 'self',
-            # since it could be a ProxyEngine
-            if lcol not in fk['constrained_columns']:
-                fk['constrained_columns'].append(lcol)
-            if rcol not in fk['referred_columns']:
-                fk['referred_columns'].append(rcol)
+            self._parse_fk(fks, fkeys, numerical_id, rtbl, lcol, rcol)
         return fkeys
 
+    def _parse_fk(self, fks, fkeys, numerical_id, rtbl, lcol, rcol):
+        # sqlite won't return rcol if the table
+        # was created with REFERENCES <tablename>, no col
+        if rcol is None:
+            rcol = lcol
+
+        if self._broken_fk_pragma_quotes:
+            rtbl = re.sub(r'^[\"\[`\']|[\"\]`\']$', '', rtbl)
+
+        try:
+            fk = fks[numerical_id]
+        except KeyError:
+            fk = {
+                'name': None,
+                'constrained_columns': [],
+                'referred_schema': None,
+                'referred_table': rtbl,
+                'referred_columns': []
+            }
+            fkeys.append(fk)
+            fks[numerical_id] = fk
+
+        # look up the table based on the given table's engine, not 'self',
+        # since it could be a ProxyEngine
+        if lcol not in fk['constrained_columns']:
+            fk['constrained_columns'].append(lcol)
+        if rcol not in fk['referred_columns']:
+            fk['referred_columns'].append(rcol)
+        return fk
+
     @reflection.cache
     def get_indexes(self, connection, table_name, schema=None, **kw):
         quote = self.identifier_preparer.quote_identifier
index 96171f4f7ce59b7b5b672bb0a0b7dae6722c5d54..97962a54a2f4ba3a5baa09845d4b5f899d573b05 100644 (file)
@@ -401,7 +401,7 @@ class DialectTest(fixtures.TestBase, AssertsExecutionResults):
             meta.drop_all()
 
     @testing.provide_metadata
-    def test_quoted_identifiers_one(self):
+    def test_quoted_identifiers_functional_one(self):
         """Tests autoload of tables created with quoted column names."""
 
         metadata = self.metadata
@@ -427,7 +427,7 @@ class DialectTest(fixtures.TestBase, AssertsExecutionResults):
                 == table2.c.id)
 
     @testing.provide_metadata
-    def test_quoted_identifiers_two(self):
+    def test_quoted_identifiers_functional_two(self):
         """"test the edgiest of edge cases, quoted table/col names
         that start and end with quotes.
 
@@ -462,6 +462,30 @@ class DialectTest(fixtures.TestBase, AssertsExecutionResults):
         #assert j.onclause.compare(table1.c['"id"']
         #        == table2.c['"aid"'])
 
+    def test_legacy_quoted_identifiers_unit(self):
+        dialect = sqlite.dialect()
+        dialect._broken_fk_pragma_quotes = True
+
+
+        for row in [
+            (0, 'target', 'tid', 'id'),
+            (0, '"target"', 'tid', 'id'),
+            (0, '[target]', 'tid', 'id'),
+            (0, "'target'", 'tid', 'id'),
+            (0, '`target`', 'tid', 'id'),
+        ]:
+            fks = {}
+            fkeys = []
+            dialect._parse_fk(fks, fkeys, *row)
+            eq_(fkeys, [{
+                    'referred_table': 'target',
+                    'referred_columns': ['id'],
+                    'referred_schema': None,
+                    'name': None,
+                    'constrained_columns': ['tid']
+                }])
+
+
     def test_attached_as_schema(self):
         cx = testing.db.connect()
         try: