Commits

jason kirtland committed 05027b9

Changed MySQL dialect to use the older LIMIT <offset>, <limit> syntax instead
of LIMIT <l> OFFSET <o> for folks using 3.23. ([ticket:794], thanks for the
patch!)

Comments (0)

Files changed (3)

 
 - Fixed reflection of the empty string for mysql enums.
 
+- Changed MySQL dialect to use the older LIMIT <offset>, <limit> syntax
+  instead of LIMIT <l> OFFSET <o> for folks using 3.23. [ticket:794]
+
 - Added 'passive_deletes="all"' flag to relation(), disables all nulling-out
   of foreign key attributes during a flush where the parent object is
   deleted.

lib/sqlalchemy/databases/mysql.py

             return super(MySQLCompiler, self).for_update_clause(select)
 
     def limit_clause(self, select):
-        text = ""
-        if select._limit is not None:
-            text +=  " \n LIMIT " + str(select._limit)
-        if select._offset is not None:
-            if select._limit is None:
-                # straight from the MySQL docs, I kid you not
-                text += " \n LIMIT 18446744073709551615"
-            text += " OFFSET " + str(select._offset)
-        return text
-        
+        # MySQL supports:
+        #   LIMIT <limit>
+        #   LIMIT <offset>, <limit>
+        # and in server versions > 3.3:
+        #   LIMIT <limit> OFFSET <offset>
+        # The latter is more readable for offsets but we're stuck with the
+        # former until we can refine dialects by server revision.
+
+        limit, offset = select._limit, select._offset
+
+        if (limit, offset) == (None, None):
+            return ''
+        elif offset is not None:
+            # As suggested by the MySQL docs, need to apply an
+            # artificial limit if one wasn't provided
+            if limit is None:
+                limit = 18446744073709551615
+            return ' \n LIMIT %s, %s' % (offset, limit)
+        else:
+            # No offset provided, so just use the limit
+            return ' \n LIMIT %s' % (limit,)
+
 
 # ug.  "InnoDB needs indexes on foreign keys and referenced keys [...].
 #       Starting with MySQL 4.1.2, these indexes are created automatically.

test/dialect/mysql.py

         enum_table.drop()
 
     @testing.supported('mysql')
+    @testing.exclude('mysql', '>', (3))
     def test_enum_parse(self):
         """More exercises for the ENUM type."""
-        
+
+        # MySQL 3.23 can't handle an ENUM of ''....
+
         db = testbase.db
         enum_table = Table('mysql_enum', MetaData(testbase.db),
             Column('e1', mysql.MSEnum("'a'")),
         self.assertEqual(got, wanted)
 
 
-class SQLTest(AssertMixin):
+class SQLTest(SQLCompileTest):
     """Tests MySQL-dialect specific compilation."""
+    __dialect__ = testbase.db.dialect
 
     @testing.supported('mysql')
     def test_precolumns(self):
             gen(True, ['high_priority', sql.text('sql_cache')]),
             'SELECT high_priority sql_cache DISTINCT q')
 
+    @testing.supported('mysql')
+    def test_limit(self):
+        t = sql.table('t', sql.column('col1'), sql.column('col2'))
+        
+        self.assert_compile(
+            select([t]).limit(10).offset(20),
+            "SELECT t.col1, t.col2 FROM t  LIMIT 20, 10"
+            )
+        self.assert_compile(
+            select([t]).limit(10),
+            "SELECT t.col1, t.col2 FROM t  LIMIT 10")
+        self.assert_compile(
+            select([t]).offset(10),
+            "SELECT t.col1, t.col2 FROM t  LIMIT 10, 18446744073709551615"
+            )
+
 
 def colspec(c):
     return testbase.db.dialect.schemagenerator(testbase.db.dialect,