]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Corrected problem with information schema not working with binary collation on mssql...
authorMichael Trier <mtrier@gmail.com>
Fri, 27 Mar 2009 21:27:34 +0000 (21:27 +0000)
committerMichael Trier <mtrier@gmail.com>
Fri, 27 Mar 2009 21:27:34 +0000 (21:27 +0000)
CHANGES
lib/sqlalchemy/databases/information_schema.py
lib/sqlalchemy/databases/mssql.py

diff --git a/CHANGES b/CHANGES
index ab09d7902f7b249dc1cfa01c29b504e014e03050..ba3bf243d5a6b269575b18967e9e0f8b5f5833c9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -12,7 +12,12 @@ CHANGES
       otherwise modified events would not be fired correctly.
       Set collection is now compatible with merge(), 
       fixes [ticket:1352].
-      
+
+- mssql
+    - Corrected problem with information schema not working with a
+      binary collation based database. Cleaned up information
+      schema since it is only used by mssql now. [ticket:1343]
+
 0.5.3
 =====
 - orm
index b15082ac2ebb6afa0b4ee97553730f19dceb3d02..670b84e46a10e83bd0c2281cc239f74e64d803cc 100644 (file)
@@ -5,179 +5,69 @@ from sqlalchemy.schema import DefaultClause, ForeignKeyConstraint
 
 ischema = MetaData()
 
-schemata = Table("schemata", ischema,
-    Column("catalog_name", String),
-    Column("schema_name", String),
-    Column("schema_owner", String),
-    schema="information_schema")
-
-tables = Table("tables", ischema,
-    Column("table_catalog", String),
-    Column("table_schema", String),
-    Column("table_name", String),
-    Column("table_type", String),
-    schema="information_schema")
-
-columns = Table("columns", ischema,
-    Column("table_schema", String),
-    Column("table_name", String),
-    Column("column_name", String),
-    Column("is_nullable", Integer),
-    Column("data_type", String),
-    Column("ordinal_position", Integer),
-    Column("character_maximum_length", Integer),
-    Column("numeric_precision", Integer),
-    Column("numeric_scale", Integer),
-    Column("column_default", Integer),
-    Column("collation_name", String),
-    schema="information_schema")
-
-constraints = Table("table_constraints", ischema,
-    Column("table_schema", String),
-    Column("table_name", String),
-    Column("constraint_name", String),
-    Column("constraint_type", String),
-    schema="information_schema")
-
-column_constraints = Table("constraint_column_usage", ischema,
-    Column("table_schema", String),
-    Column("table_name", String),
-    Column("column_name", String),
-    Column("constraint_name", String),
-    schema="information_schema")
-
-pg_key_constraints = Table("key_column_usage", ischema,
-    Column("table_schema", String),
-    Column("table_name", String),
-    Column("column_name", String),
-    Column("constraint_name", String),
-    Column("ordinal_position", Integer),
-    schema="information_schema")
-
-#mysql_key_constraints = Table("key_column_usage", ischema,
-#    Column("table_schema", String),
-#    Column("table_name", String),
-#    Column("column_name", String),
-#    Column("constraint_name", String),
-#    Column("referenced_table_schema", String),
-#    Column("referenced_table_name", String),
-#    Column("referenced_column_name", String),
-#    schema="information_schema")
-
-key_constraints = pg_key_constraints
-
-ref_constraints = Table("referential_constraints", ischema,
-    Column("constraint_catalog", String),
-    Column("constraint_schema", String),
-    Column("constraint_name", String),
-    Column("unique_constraint_catlog", String),
-    Column("unique_constraint_schema", String),
-    Column("unique_constraint_name", String),
-    Column("match_option", String),
-    Column("update_rule", String),
-    Column("delete_rule", String),
-    schema="information_schema")
+schemata = Table("SCHEMATA", ischema,
+    Column("CATALOG_NAME", String, key="catalog_name"),
+    Column("SCHEMA_NAME", String, key="schema_name"),
+    Column("SCHEMA_OWNER", String, key="schema_owner"),
+    schema="INFORMATION_SCHEMA")
+
+tables = Table("TABLES", ischema,
+    Column("TABLE_CATALOG", String, key="table_catalog"),
+    Column("TABLE_SCHEMA", String, key="table_schema"),
+    Column("TABLE_NAME", String, key="table_name"),
+    Column("TABLE_TYPE", String, key="table_type"),
+    schema="INFORMATION_SCHEMA")
+
+columns = Table("COLUMNS", ischema,
+    Column("TABLE_SCHEMA", String, key="table_schema"),
+    Column("TABLE_NAME", String, key="table_name"),
+    Column("COLUMN_NAME", String, key="column_name"),
+    Column("IS_NULLABLE", Integer, key="is_nullable"),
+    Column("DATA_TYPE", String, key="data_type"),
+    Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
+    Column("CHARACTER_MAXIMUM_LENGTH", Integer, key="character_maximum_length"),
+    Column("NUMERIC_PRECISION", Integer, key="numeric_precision"),
+    Column("NUMERIC_SCALE", Integer, key="numeric_scale"),
+    Column("COLUMN_DEFAULT", Integer, key="column_default"),
+    Column("COLLATION_NAME", String, key="collation_name"),
+    schema="INFORMATION_SCHEMA")
+
+constraints = Table("TABLE_CONSTRAINTS", ischema,
+    Column("TABLE_SCHEMA", String, key="table_schema"),
+    Column("TABLE_NAME", String, key="table_name"),
+    Column("CONSTRAINT_NAME", String, key="constraint_name"),
+    Column("CONSTRAINT_TYPE", String, key="constraint_type"),
+    schema="INFORMATION_SCHEMA")
+
+column_constraints = Table("CONSTRAINT_COLUMN_USAGE", ischema,
+    Column("TABLE_SCHEMA", String, key="table_schema"),
+    Column("TABLE_NAME", String, key="table_name"),
+    Column("COLUMN_NAME", String, key="column_name"),
+    Column("CONSTRAINT_NAME", String, key="constraint_name"),
+    schema="INFORMATION_SCHEMA")
+
+key_constraints = Table("KEY_COLUMN_USAGE", ischema,
+    Column("TABLE_SCHEMA", String, key="table_schema"),
+    Column("TABLE_NAME", String, key="table_name"),
+    Column("COLUMN_NAME", String, key="column_name"),
+    Column("CONSTRAINT_NAME", String, key="constraint_name"),
+    Column("ORDINAL_POSITION", Integer, key="ordinal_position"),
+    schema="INFORMATION_SCHEMA")
+
+ref_constraints = Table("REFERENTIAL_CONSTRAINTS", ischema,
+    Column("CONSTRAINT_CATALOG", String, key="constraint_catalog"),
+    Column("CONSTRAINT_SCHEMA", String, key="constraint_schema"),
+    Column("CONSTRAINT_NAME", String, key="constraint_name"),
+    Column("UNIQUE_CONSTRAINT_CATLOG", String, key="unique_constraint_catalog"),
+    Column("UNIQUE_CONSTRAINT_SCHEMA", String, key="unique_constraint_schema"),
+    Column("UNIQUE_CONSTRAINT_NAME", String, key="unique_constraint_name"),
+    Column("MATCH_OPTION", String, key="match_option"),
+    Column("UPDATE_RULE", String, key="update_rule"),
+    Column("DELETE_RULE", String, key="delete_rule"),
+    schema="INFORMATION_SCHEMA")
 
 
 def table_names(connection, schema):
     s = select([tables.c.table_name], tables.c.table_schema==schema)
     return [row[0] for row in connection.execute(s)]
 
-
-def reflecttable(connection, table, include_columns, ischema_names):
-    key_constraints = pg_key_constraints
-
-    if table.schema is not None:
-        current_schema = table.schema
-    else:
-        current_schema = connection.default_schema_name()
-
-    s = select([columns],
-        sql.and_(columns.c.table_name==table.name,
-        columns.c.table_schema==current_schema),
-        order_by=[columns.c.ordinal_position])
-
-    c = connection.execute(s)
-    found_table = False
-    while True:
-        row = c.fetchone()
-        if row is None:
-            break
-        #print "row! " + repr(row)
- #       continue
-        found_table = True
-        (name, type, nullable, charlen, numericprec, numericscale, default) = (
-            row[columns.c.column_name],
-            row[columns.c.data_type],
-            row[columns.c.is_nullable] == 'YES',
-            row[columns.c.character_maximum_length],
-            row[columns.c.numeric_precision],
-            row[columns.c.numeric_scale],
-            row[columns.c.column_default]
-            )
-        if include_columns and name not in include_columns:
-            continue
-
-        args = []
-        for a in (charlen, numericprec, numericscale):
-            if a is not None:
-                args.append(a)
-        coltype = ischema_names[type]
-        #print "coltype " + repr(coltype) + " args " +  repr(args)
-        coltype = coltype(*args)
-        colargs = []
-        if default is not None:
-            colargs.append(DefaultClause(sql.text(default)))
-        table.append_column(Column(name, coltype, nullable=nullable, *colargs))
-
-    if not found_table:
-        raise exc.NoSuchTableError(table.name)
-
-    # we are relying on the natural ordering of the constraint_column_usage table to return the referenced columns
-    # in an order that corresponds to the ordinal_position in the key_constraints table, otherwise composite foreign keys
-    # wont reflect properly.  dont see a way around this based on whats available from information_schema
-    s = select([constraints.c.constraint_name, constraints.c.constraint_type, constraints.c.table_name, key_constraints], use_labels=True, from_obj=[constraints.join(column_constraints, column_constraints.c.constraint_name==constraints.c.constraint_name).join(key_constraints, key_constraints.c.constraint_name==column_constraints.c.constraint_name)], order_by=[key_constraints.c.ordinal_position])
-    s.append_column(column_constraints)
-    s.append_whereclause(constraints.c.table_name==table.name)
-    s.append_whereclause(constraints.c.table_schema==current_schema)
-    colmap = [constraints.c.constraint_type, key_constraints.c.column_name, column_constraints.c.table_schema, column_constraints.c.table_name, column_constraints.c.column_name, constraints.c.constraint_name, key_constraints.c.ordinal_position]
-    c = connection.execute(s)
-
-    fks = {}
-    while True:
-        row = c.fetchone()
-        if row is None:
-            break
-        (type, constrained_column, referred_schema, referred_table, referred_column, constraint_name, ordinal_position) = (
-            row[colmap[0]],
-            row[colmap[1]],
-            row[colmap[2]],
-            row[colmap[3]],
-            row[colmap[4]],
-            row[colmap[5]],
-            row[colmap[6]]
-        )
-        #print "type %s on column %s to remote %s.%s.%s" % (type, constrained_column, referred_schema, referred_table, referred_column)
-        if type == 'PRIMARY KEY':
-            table.primary_key.add(table.c[constrained_column])
-        elif type == 'FOREIGN KEY':
-            try:
-                fk = fks[constraint_name]
-            except KeyError:
-                fk = ([], [])
-                fks[constraint_name] = fk
-            if current_schema == referred_schema:
-                referred_schema = table.schema
-            if referred_schema is not None:
-                Table(referred_table, table.metadata, autoload=True, schema=referred_schema, autoload_with=connection)
-                refspec = ".".join([referred_schema, referred_table, referred_column])
-            else:
-                Table(referred_table, table.metadata, autoload=True, autoload_with=connection)
-                refspec = ".".join([referred_table, referred_column])
-            if constrained_column not in fk[0]:
-                fk[0].append(constrained_column)
-            if refspec not in fk[1]:
-                fk[1].append(refspec)
-
-    for name, value in fks.iteritems():
-        table.append_constraint(ForeignKeyConstraint(value[0], value[1], name=name))
index 5ea22251f010bc62734b5a077497cf7d224270e3..ccf0c4f800a55c6df5552cf996e3be6f1af652c3 100644 (file)
@@ -827,9 +827,9 @@ def _has_implicit_sequence(column):
         isinstance(column.type, sqltypes.Integer) and \
         not column.foreign_keys and \
         (
-            column.default is None or 
+            column.default is None or
             (
-                isinstance(column.default, schema.Sequence) and 
+                isinstance(column.default, schema.Sequence) and
                 column.default.optional)
             )
 
@@ -859,7 +859,7 @@ class MSSQLExecutionContext(default.DefaultExecutionContext):
                 self.IINSERT = False
 
             if self.IINSERT:
-                self.cursor.execute("SET IDENTITY_INSERT %s ON" % 
+                self.cursor.execute("SET IDENTITY_INSERT %s ON" %
                     self.dialect.identifier_preparer.format_table(self.compiled.statement.table))
 
     def handle_dbapi_exception(self, e):
@@ -1089,21 +1089,11 @@ class MSSQLDialect(default.DefaultDialect):
         from sqlalchemy.databases import information_schema as ischema
         return ischema.table_names(connection, schema)
 
-    def uppercase_table(self, t):
-        # convert all names to uppercase -- fixes refs to INFORMATION_SCHEMA for case-senstive DBs, and won't matter for case-insensitive
-        t.name = t.name.upper()
-        if t.schema:
-            t.schema = t.schema.upper()
-        for c in t.columns:
-            c.name = c.name.upper()
-        return t
-
-
     def has_table(self, connection, tablename, schema=None):
         import sqlalchemy.databases.information_schema as ischema
 
         current_schema = schema or self.get_default_schema_name(connection)
-        columns = self.uppercase_table(ischema.columns)
+        columns = ischema.columns
         s = sql.select([columns],
                    current_schema
                        and sql.and_(columns.c.table_name==tablename, columns.c.table_schema==current_schema)
@@ -1122,7 +1112,7 @@ class MSSQLDialect(default.DefaultDialect):
         else:
             current_schema = self.get_default_schema_name(connection)
 
-        columns = self.uppercase_table(ischema.columns)
+        columns = ischema.columns
         s = sql.select([columns],
                    current_schema
                        and sql.and_(columns.c.table_name==table.name, columns.c.table_schema==current_schema)
@@ -1205,10 +1195,10 @@ class MSSQLDialect(default.DefaultDialect):
                 pass
 
         # Add constraints
-        RR = self.uppercase_table(ischema.ref_constraints)    #information_schema.referential_constraints
-        TC = self.uppercase_table(ischema.constraints)        #information_schema.table_constraints
-        C  = self.uppercase_table(ischema.pg_key_constraints).alias('C') #information_schema.constraint_column_usage: the constrained column
-        R  = self.uppercase_table(ischema.pg_key_constraints).alias('R') #information_schema.constraint_column_usage: the referenced column
+        RR = ischema.ref_constraints    #information_schema.referential_constraints
+        TC = ischema.constraints        #information_schema.table_constraints
+        C  = ischema.key_constraints.alias('C') #information_schema.constraint_column_usage: the constrained column
+        R  = ischema.key_constraints.alias('R') #information_schema.constraint_column_usage: the referenced column
 
         # Primary key constraints
         s = sql.select([C.c.column_name, TC.c.constraint_type], sql.and_(TC.c.constraint_name == C.c.constraint_name,
@@ -1299,7 +1289,7 @@ class MSSQLDialect_pymssql(MSSQLDialect):
             if self.dbapi.version_info > (0, 8, 0):
                 r[1]['timeout'] = self.query_timeout
             else:
-                self.dbapi._mssql.set_query_timeout(self.query_timeout) 
+                self.dbapi._mssql.set_query_timeout(self.query_timeout)
         return r
 
     def make_connect_string(self, keys, query):
@@ -1375,10 +1365,10 @@ class MSSQLDialect_pyodbc(MSSQLDialect):
             else:
                 connectors.append("TrustedConnection=Yes")
 
-            # if set to 'Yes', the ODBC layer will try to automagically convert 
-            # textual data from your database encoding to your client encoding 
-            # This should obviously be set to 'No' if you query a cp1253 encoded 
-            # database from a latin1 client... 
+            # if set to 'Yes', the ODBC layer will try to automagically convert
+            # textual data from your database encoding to your client encoding
+            # This should obviously be set to 'No' if you query a cp1253 encoded
+            # database from a latin1 client...
             if 'odbc_autotranslate' in keys:
                 connectors.append("AutoTranslate=%s" % keys.pop("odbc_autotranslate"))
 
@@ -1474,7 +1464,7 @@ class MSSQLCompiler(compiler.DefaultCompiler):
         """ MS-SQL puts TOP, it's version of LIMIT here """
         if select._distinct or select._limit:
             s = select._distinct and "DISTINCT " or ""
-            
+
             if select._limit:
                 if not select._offset:
                     s += "TOP %s " % (select._limit,)
@@ -1632,10 +1622,10 @@ class MSSQLSchemaGenerator(compiler.SchemaGenerator):
                 colspec += " NOT NULL"
             else:
                 colspec += " NULL"
-        
+
         if not column.table:
             raise exc.InvalidRequestError("mssql requires Table-bound columns in order to generate DDL")
-            
+
         seq_col = _table_sequence_column(column.table)
 
         # install a IDENTITY Sequence if we have an implicit IDENTITY column