]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- added autoincrement=True to Column; will disable schema generation
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 23 Sep 2006 17:21:56 +0000 (17:21 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 23 Sep 2006 17:21:56 +0000 (17:21 +0000)
of SERIAL/AUTO_INCREMENT/identity seq for postgres/mysql/mssql if
explicitly set to False.  #303

CHANGES
lib/sqlalchemy/databases/mssql.py
lib/sqlalchemy/databases/mysql.py
lib/sqlalchemy/databases/postgres.py
lib/sqlalchemy/schema.py
test/sql/defaults.py

diff --git a/CHANGES b/CHANGES
index 10ef7968b1b989dc2c5bbd46edc5cdc1f843b093..e077877c36b337b41754674712e84d302df39bee 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -34,6 +34,9 @@ preventing conflicts with lazy loader operation, fixes
 - added "batch=True" flag to mapper; if False, save_obj
 will fully save one object at a time including calls
 to before_XXXX and after_XXXX
+- added autoincrement=True to Column; will disable schema generation
+of SERIAL/AUTO_INCREMENT/identity seq for postgres/mysql/mssql if
+explicitly set to False
 
 0.2.8
 - cleanup on connection methods + documentation.  custom DBAPI
index 1a30b9fe5b249ea3c0a168bea73bc252b9486f75..6c4fa816c80f0c2a4f34df1bf5939fd88f09c8ee 100644 (file)
@@ -520,7 +520,7 @@ class MSSQLSchemaGenerator(ansisql.ANSISchemaGenerator):
         colspec = self.preparer.format_column(column) + " " + column.type.engine_impl(self.engine).get_col_spec()
 
         # install a IDENTITY Sequence if we have an implicit IDENTITY column
-        if column.primary_key and isinstance(column.type, sqltypes.Integer):
+        if column.primary_key and column.autoincrement and isinstance(column.type, sqltypes.Integer):
             if column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional):
                 column.sequence = schema.Sequence(column.name + '_seq')
 
index 74821707f4633a55295a804eceaeea835a901d3a..f833489d224071efc3ce6c2f09e802dd33e056cc 100644 (file)
@@ -439,7 +439,7 @@ class MySQLSchemaGenerator(ansisql.ANSISchemaGenerator):
         if not column.nullable:
             colspec += " NOT NULL"
         if column.primary_key:
-            if not column.foreign_key and first_pk and isinstance(column.type, sqltypes.Integer):
+            if not column.foreign_key and first_pk and column.autoincrement and isinstance(column.type, sqltypes.Integer):
                 colspec += " AUTO_INCREMENT"
         return colspec
 
index 7bf7869766dd6a73a30e2f27a555a1e17ab673b4..6fe51ad9afd19fe902f0086a2bb7ba16e696fd1e 100644 (file)
@@ -490,7 +490,7 @@ class PGSchemaGenerator(ansisql.ANSISchemaGenerator):
         
     def get_column_specification(self, column, **kwargs):
         colspec = self.preparer.format_column(column)
-        if column.primary_key and not column.foreign_key and isinstance(column.type, sqltypes.Integer) and not isinstance(column.type, sqltypes.SmallInteger) and (column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional)):
+        if column.primary_key and not column.foreign_key and column.autoincrement and isinstance(column.type, sqltypes.Integer) and not isinstance(column.type, sqltypes.SmallInteger) and (column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional)):
             colspec += " SERIAL"
         else:
             colspec += " " + column.type.engine_impl(self.engine).get_col_spec()
@@ -520,7 +520,7 @@ class PGDefaultRunner(ansisql.ANSIDefaultRunner):
             if isinstance(column.default, schema.PassiveDefault):
                 c = self.proxy("select %s" % column.default.arg)
                 return c.fetchone()[0]
-            elif isinstance(column.type, sqltypes.Integer) and (column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional)):
+            elif (isinstance(column.type, sqltypes.Integer) and column.autoincrement) and (column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional)):
                 sch = column.table.schema
                 # TODO: this has to build into the Sequence object so we can get the quoting 
                 # logic from it
index 3cbb7f9e461b970dddc613f1b7901483a0b680f5..3ee03f1eedd544fda4f4dbc51f7902f5f47e4084 100644 (file)
@@ -367,14 +367,15 @@ class Column(SchemaItem, sql.ColumnClause):
         Generated SQL, however, will still reference the column by its actual name.
         
         primary_key=False : True if this column is a primary key column.  Multiple columns can have this flag
-        set to specify composite primary keys.
+        set to specify composite primary keys.  As an alternative, the primary key of a Table can be specified
+        via an explicit PrimaryKeyConstraint instance appended to the Table's list of objects.
         
         nullable=True : True if this column should allow nulls. Defaults to True unless this column is a primary
         key column.
         
         default=None : a scalar, python callable, or ClauseElement representing the "default value" for this column,
         which will be invoked upon insert if this column is not present in the insert list or is given a value
-        of None.
+        of None.  The default expression will be converted into a ColumnDefault object upon initialization.
 
         hidden=False : indicates this column should not be listed in the
         table's list of columns.  Used for the "oid" column, which generally
@@ -392,8 +393,17 @@ class Column(SchemaItem, sql.ColumnClause):
         specify the same index name will all be included in the index, in the
         order of their creation.
 
+        autoincrement=True : Indicates that integer-based primary key columns should have autoincrementing behavior,
+        if supported by the underlying database.  This will affect CREATE TABLE statements such that they will
+        use the databases "auto-incrementing" keyword (such as SERIAL for postgres, AUTO_INCREMENT for mysql) and will
+        also affect the behavior of some dialects during INSERT statement execution such that they will assume primary 
+        key values are created in this manner.  If a Column has an explicit ColumnDefault object (such as via the 
+        "default" keyword, or a Sequence or PassiveDefault), then the value of autoincrement is ignored and is assumed 
+        to be False.  autoincrement value is only significant for a column with a type or subtype of Integer.
+        
         quote=False : indicates that the Column identifier must be properly escaped and quoted before being sent 
-        to the database.
+        to the database.  This flag should normally not be required as dialects can auto-detect conditions where quoting
+        is required.
 
         case_sensitive=True : indicates that the identifier should be interpreted by the database in the natural case for identifiers.
         Mixed case is not sufficient to cause this identifier to be quoted; it must contain an illegal character.
@@ -411,6 +421,7 @@ class Column(SchemaItem, sql.ColumnClause):
         self.quote = kwargs.pop('quote', False)
         self._set_casing_strategy(name, kwargs)
         self.onupdate = kwargs.pop('onupdate', None)
+        self.autoincrement = kwargs.pop('autoincrement', True)
         self.__originating_column = self
         if self.index is not None and self.unique is not None:
             raise exceptions.ArgumentError("Column may not define both index and unique")
index 57b4388a197248a5fc08c0fd22b26f546269ed40..57de15c914c9d2ca1bc9d905f100eba3d9fb6034 100644 (file)
@@ -120,12 +120,44 @@ class DefaultTest(PersistTest):
         l = t.select(t.c.col1==pk).execute()
         l = l.fetchone()
         self.assert_(l['col3'] == 55)
-        
-class SequenceTest(PersistTest):
 
+class AutoIncrementTest(PersistTest):
+    @testbase.supported('postgres', 'mysql')
+    def testnonautoincrement(self):
+        meta = BoundMetaData(testbase.db)
+        nonai_table = Table("aitest", meta, 
+            Column('id', Integer, autoincrement=False, primary_key=True),
+            Column('data', String(20)))
+        nonai_table.create()
+        try:
+            try:
+                # postgres will fail on first row, mysql fails on second row
+                nonai_table.insert().execute(data='row 1')
+                nonai_table.insert().execute(data='row 2')
+                assert False
+            except exceptions.SQLError, e:
+                print "Got exception", str(e)
+                assert True
+                
+            nonai_table.insert().execute(id=1, data='row 1')
+        finally:
+            nonai_table.drop()    
+
+    def testwithautoincrement(self):
+        meta = BoundMetaData(testbase.db)
+        table = Table("aitest", meta, 
+            Column('id', Integer, primary_key=True),
+            Column('data', String(20)))
+        table.create()
+        try:
+            table.insert().execute(data='row 1')
+            table.insert().execute(data='row 2')
+        finally:
+            table.drop()    
+
+class SequenceTest(PersistTest):
+    @testbase.supported('postgres', 'oracle')
     def setUpAll(self):
-        if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle':
-            return
         global cartitems
         cartitems = Table("cartitems", db, 
             Column("cart_id", Integer, Sequence('cart_id_seq'), primary_key=True),
@@ -159,9 +191,8 @@ class SequenceTest(PersistTest):
         x = cartitems.c.cart_id.sequence.execute()
         self.assert_(1 <= x <= 4)
         
+    @testbase.supported('postgres', 'oracle')
     def tearDownAll(self): 
-        if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle':
-            return
         cartitems.drop()
 
 if __name__ == "__main__":