]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The "start" and "increment" attributes on Sequence now
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 3 Nov 2009 18:33:57 +0000 (18:33 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 3 Nov 2009 18:33:57 +0000 (18:33 +0000)
generate "START WITH" and "INCREMENT BY" by default,
on Oracle and Postgresql.  Firebird doesn't support
these keywords right now.  [ticket:1545]

CHANGES
lib/sqlalchemy/dialects/firebird/base.py
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/sql/compiler.py
test/sql/test_defaults.py

diff --git a/CHANGES b/CHANGES
index ee1f894b257f1fffc4bb69e97dfec1811e8b603f..cc56b3a18b2cdea53d275684bf3755f877b4ceff 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -303,7 +303,12 @@ CHANGES
         - PrimaryKeyConstraint.remove()
       These should be constructed declaratively (i.e. in one
       construction).
-
+    
+    - The "start" and "increment" attributes on Sequence now
+      generate "START WITH" and "INCREMENT BY" by default,
+      on Oracle and Postgresql.  Firebird doesn't support
+      these keywords right now.  [ticket:1545]
+      
     - UniqueConstraint, Index, PrimaryKeyConstraint all accept
       lists of column names or column objects as arguments.
 
index 232583c39eb5ca23cccfa7570d015f2bc5452655..921c70e980144c903db9a43f727d102c87a02cf3 100644 (file)
@@ -271,7 +271,14 @@ class FBDDLCompiler(sql.compiler.DDLCompiler):
 
     def visit_create_sequence(self, create):
         """Generate a ``CREATE GENERATOR`` statement for the sequence."""
-
+        
+        # no syntax for these
+        # http://www.firebirdsql.org/manual/generatorguide-sqlsyntax.html
+        if create.element.start is not None:
+            raise NotImplemented("Firebird SEQUENCE doesn't support START WITH")
+        if create.element.increment is not None:
+            raise NotImplemented("Firebird SEQUENCE doesn't support INCREMENT BY")
+            
         if self.dialect._version_two:
             return "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element)
         else:
index 7b141ed2357c46294ea0463d6ed4c6612b3fd1cc..22ba2ce934e821372f4911053672214d95944cdc 100644 (file)
@@ -441,12 +441,6 @@ class OracleCompiler(compiler.SQLCompiler):
 
 class OracleDDLCompiler(compiler.DDLCompiler):
 
-    def visit_create_sequence(self, create):
-        return "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element)
-
-    def visit_drop_sequence(self, drop):
-        return "DROP SEQUENCE %s" % self.preparer.format_sequence(drop.element)
-
     def define_constraint_cascades(self, constraint):
         text = ""
         if constraint.ondelete is not None:
index bc8cff90525340c6acae3038c77c2ecce5d43e14..97108b3cbb9b04a00f809ce5908c2008969ca0af 100644 (file)
@@ -340,12 +340,6 @@ class PGDDLCompiler(compiler.DDLCompiler):
             colspec += " NOT NULL"
         return colspec
 
-    def visit_create_sequence(self, create):
-        return "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element)
-            
-    def visit_drop_sequence(self, drop):
-        return "DROP SEQUENCE %s" % self.preparer.format_sequence(drop.element)
-        
     def visit_enum_constraint(self, constraint):
         if not constraint.type.native_enum:
             return super(PGDDLCompiler, self).visit_enum_constraint(constraint)
index 088ca19695b8bb49a353ad07b607dd43ff31d8f3..6802bfbefc8d0d6b8e5718bc1117e9e601650749 100644 (file)
@@ -1024,7 +1024,18 @@ class DDLCompiler(engine.Compiled):
             self.preparer.format_table(create.element.table),
             self.process(create.element)
         )
+
+    def visit_create_sequence(self, create):
+        text = "CREATE SEQUENCE %s" % self.preparer.format_sequence(create.element)
+        if create.element.increment is not None:
+            text += " INCREMENT BY %d" % create.element.increment
+        if create.element.start is not None:
+            text += " START WITH %d" % create.element.start
+        return text
         
+    def visit_drop_sequence(self, drop):
+        return "DROP SEQUENCE %s" % self.preparer.format_sequence(drop.element)
+
     def visit_drop_constraint(self, drop):
         preparer = self.preparer
         return "ALTER TABLE %s DROP CONSTRAINT %s%s" % (
index 04809b48aec304ee7fc896178bffb45ff9383d4c..092c7640e3c2a9c5b993095bf3ef76cc24e3d6ff 100644 (file)
@@ -1,6 +1,7 @@
 from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message
 import datetime
 from sqlalchemy import Sequence, Column, func
+from sqlalchemy.schema import CreateSequence, DropSequence
 from sqlalchemy.sql import select, text
 import sqlalchemy as sa
 from sqlalchemy.test import testing, engines
@@ -535,10 +536,10 @@ class AutoIncrementTest(_base.TablesTest):
         nonai.insert().execute(id=1, data='row 1')
 
 
-class SequenceTest(testing.TestBase):
-    __requires__ = ('sequences',)
+class SequenceTest(testing.TestBase, testing.AssertsCompiledSQL):
 
     @classmethod
+    @testing.requires.sequences
     def setup_class(cls):
         global cartitems, sometable, metadata
         metadata = MetaData(testing.db)
@@ -556,7 +557,60 @@ class SequenceTest(testing.TestBase):
 
         metadata.create_all()
 
-    def testseqnonpk(self):
+
+    def test_compile(self):
+        self.assert_compile(
+            CreateSequence(Sequence('foo_seq')),
+            "CREATE SEQUENCE foo_seq",
+            use_default_dialect=True,
+        )
+
+        self.assert_compile(
+            CreateSequence(Sequence('foo_seq', start=5)),
+            "CREATE SEQUENCE foo_seq START WITH 5",
+            use_default_dialect=True,
+        )
+
+        self.assert_compile(
+            CreateSequence(Sequence('foo_seq', increment=2)),
+            "CREATE SEQUENCE foo_seq INCREMENT BY 2",
+            use_default_dialect=True,
+        )
+
+        self.assert_compile(
+            CreateSequence(Sequence('foo_seq', increment=2, start=5)),
+            "CREATE SEQUENCE foo_seq INCREMENT BY 2 START WITH 5",
+            use_default_dialect=True,
+        )
+
+        self.assert_compile(
+            DropSequence(Sequence('foo_seq')),
+            "DROP SEQUENCE foo_seq",
+            use_default_dialect=True,
+        )
+        
+
+    @testing.fails_on('firebird', 'no FB support for start/increment')
+    @testing.requires.sequences
+    def test_start_increment(self):
+        for seq in (
+                Sequence('foo_seq'), 
+                Sequence('foo_seq', start=8), 
+                Sequence('foo_seq', increment=5)):
+            seq.create(testing.db)
+            try:
+                values = [
+                    testing.db.execute(seq) for i in range(3)
+                ]
+                start = seq.start or 1
+                inc = seq.increment or 1
+                assert values == list(xrange(start, start + inc * 3, inc))
+                
+            finally:
+                seq.drop(testing.db)
+        
+    @testing.requires.sequences
+    def test_seq_nonpk(self):
         """test sequences fire off as defaults on non-pk columns"""
 
         engine = engines.testing_engine(options={'implicit_returning':False})
@@ -576,7 +630,8 @@ class SequenceTest(testing.TestBase):
              (3, "name3", 3),
              (4, "name4", 4)])
 
-    def testsequence(self):
+    @testing.requires.sequences
+    def test_sequence(self):
         cartitems.insert().execute(description='hi')
         cartitems.insert().execute(description='there')
         r = cartitems.insert().execute(description='lala')
@@ -594,6 +649,7 @@ class SequenceTest(testing.TestBase):
     @testing.fails_on('maxdb', 'FIXME: unknown')
     # maxdb db-api seems to double-execute NEXTVAL internally somewhere,
     # throwing off the numbers for these tests...
+    @testing.requires.sequences
     def test_implicit_sequence_exec(self):
         s = Sequence("my_sequence", metadata=MetaData(testing.db))
         s.create()
@@ -604,6 +660,7 @@ class SequenceTest(testing.TestBase):
             s.drop()
 
     @testing.fails_on('maxdb', 'FIXME: unknown')
+    @testing.requires.sequences
     def teststandalone_explicit(self):
         s = Sequence("my_sequence")
         s.create(bind=testing.db)
@@ -613,6 +670,7 @@ class SequenceTest(testing.TestBase):
         finally:
             s.drop(testing.db)
 
+    @testing.requires.sequences
     def test_checkfirst(self):
         s = Sequence("my_sequence")
         s.create(testing.db, checkfirst=False)
@@ -621,11 +679,13 @@ class SequenceTest(testing.TestBase):
         s.drop(testing.db, checkfirst=True)
 
     @testing.fails_on('maxdb', 'FIXME: unknown')
+    @testing.requires.sequences
     def teststandalone2(self):
         x = cartitems.c.cart_id.default.execute()
         self.assert_(1 <= x <= 4)
 
     @classmethod
+    @testing.requires.sequences
     def teardown_class(cls):
         metadata.drop_all()