]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Autodetect mysql's ANSI_QUOTES mode, sometimes. [ticket:845]
authorJason Kirtland <jek@discorporate.us>
Tue, 5 Feb 2008 17:26:35 +0000 (17:26 +0000)
committerJason Kirtland <jek@discorporate.us>
Tue, 5 Feb 2008 17:26:35 +0000 (17:26 +0000)
  The dialect needs a hook run on first pool connect to detect this most of
  the time, and a refactor with Dialect-per-Connection to get it right all of
  the time. (It's a connection-session scoped setting with dialect-modifying
  behavior)

CHANGES
lib/sqlalchemy/databases/mysql.py

diff --git a/CHANGES b/CHANGES
index 4b202edd38535597882fe7d9679a1893870cc7ae..0b0d3c3ca1524b2c36b071e797f8e684e44f6c43 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -198,6 +198,11 @@ CHANGES
     - Warnings are now issued as type exceptions.SAWarning.
 
 - dialects
+    - Auto-detect an unspecified MySQL ANSI_QUOTES mode during
+      reflection operations, support for changing the mode
+      midstream.  Manual mode setting is still required if no
+      reflection is used.
+
     - Finally added PGMacAddr type to postgres [ticket:580]
 
     - Reflect the sequence associated to a PK field (typically
index e01cec2ab77d6109f9753f580d872212b2b9ce5f..314cb8dac8cbf5580e2b7a070beb8ffdd6f98af6 100644 (file)
@@ -95,6 +95,16 @@ by supplying ``--sql-mode`` to ``mysqld``.  You can also use a ``Pool`` hook
 to issue a ``SET SESSION sql_mode='...'`` on connect to configure each
 connection.
 
+If you do not specify 'use_ansiquotes', the regular MySQL quoting style is
+used by default.  Table reflection operations will query the server 
+
+If you do issue a 'SET sql_mode' through SQLAlchemy, the dialect must be
+updated if the quoting style is changed.  Again, this change will affect all
+connections::
+
+  connection.execute('SET sql_mode="ansi"')
+  connection.dialect.use_ansiquotes = True
+
 For normal SQLAlchemy usage, loading this module is unnescesary.  It will be
 loaded on-demand when a MySQL connection is needed.  The generic column types
 like ``String`` and ``Integer`` will automatically be adapted to the optimal
@@ -1401,13 +1411,9 @@ class MySQLDialect(default.DefaultDialect):
     max_identifier_length = 255
     supports_sane_rowcount = True
 
-    def __init__(self, use_ansiquotes=False, **kwargs):
+    def __init__(self, use_ansiquotes=None, **kwargs):
         self.use_ansiquotes = use_ansiquotes
         kwargs.setdefault('default_paramstyle', 'format')
-        if self.use_ansiquotes:
-            self.preparer = MySQLANSIIdentifierPreparer
-        else:
-            self.preparer = MySQLIdentifierPreparer
         default.DefaultDialect.__init__(self, **kwargs)
 
     def dbapi(cls):
@@ -1546,6 +1552,7 @@ class MySQLDialect(default.DefaultDialect):
         """Return a Unicode SHOW TABLES from a given schema."""
 
         charset = self._detect_charset(connection)
+        self._autoset_identifier_style(connection)
         rp = connection.execute("SHOW TABLES FROM %s" %
             self.identifier_preparer.quote_identifier(schema))
         return [row[0] for row in _compat_fetchall(rp, charset=charset)]
@@ -1558,7 +1565,10 @@ class MySQLDialect(default.DefaultDialect):
         # based on platform.  DESCRIBE is slower.
 
         # [ticket:726]
-        # full_name = self.identifier_preparer.format_table(table, use_schema=True)
+        # full_name = self.identifier_preparer.format_table(table,
+        #                                                   use_schema=True)
+
+        self._autoset_identifier_style(connection)
 
         full_name = '.'.join(self.identifier_preparer._quote_free_identifiers(
             schema, table_name))
@@ -1627,12 +1637,18 @@ class MySQLDialect(default.DefaultDialect):
         """Load column definitions from the server."""
 
         charset = self._detect_charset(connection)
+        self._autoset_identifier_style(connection)
 
         try:
             reflector = self.reflector
         except AttributeError:
-            self.reflector = reflector = \
-                MySQLSchemaReflector(self.identifier_preparer)
+            preparer = self.identifier_preparer
+            if (self.server_version_info(connection) < (4, 1) and
+                self.use_ansiquotes):
+                # ANSI_QUOTES doesn't affect SHOW CREATE TABLE on < 4.1
+                preparer = MySQLIdentifierPreparer(self)
+
+            self.reflector = reflector = MySQLSchemaReflector(preparer)
 
         sql = self._show_create_table(connection, table, charset)
         if sql.startswith('CREATE ALGORITHM'):
@@ -1750,6 +1766,49 @@ class MySQLDialect(default.DefaultDialect):
             connection.info['collations'] = collations
             return collations
 
+    def use_ansiquotes(self, useansi):
+        self._use_ansiquotes = useansi
+        if useansi:
+            self.preparer = MySQLANSIIdentifierPreparer
+        else:
+            self.preparer = MySQLIdentifierPreparer
+        # icky
+        if hasattr(self, 'identifier_preparer'):
+            self.identifier_preparer = self.preparer(self)
+        if hasattr(self, 'reflector'):
+            del self.reflector
+
+    use_ansiquotes = property(lambda s: s._use_ansiquotes, use_ansiquotes,
+                              doc="True if ANSI_QUOTES is in effect.")
+
+    def _autoset_identifier_style(self, connection, charset=None):
+        """Detect and adjust for the ANSI_QUOTES sql mode.
+
+        If the dialect's use_ansiquotes is unset, query the server's sql mode
+        and reset the identifier style.
+
+        Note that this currently *only* runs during reflection.  Ideally this
+        would run the first time a connection pool connects to the database,
+        but the infrastructure for that is not yet in place.
+        """
+
+        if self.use_ansiquotes is not None:
+            return
+
+        row = _compat_fetchone(
+            connection.execute("SHOW VARIABLES LIKE 'sql_mode'",
+                               charset=charset))
+        if not row:
+            mode = ''
+        else:
+            mode = row[1] or ''
+            # 4.0
+            if mode.isdigit():
+                mode_no = int(mode)
+                mode = (mode_no | 4 == mode_no) and 'ANSI_QUOTES' or ''
+
+        self.use_ansiquotes = 'ANSI_QUOTES' in mode
+
     def _show_create_table(self, connection, table, charset=None,
                            full_name=None):
         """Run SHOW CREATE TABLE for a ``Table``."""