1 | | def get_table_list(cursor): |
2 | | raise NotImplementedError |
| 1 | # Tested against MSDE and SQL Server 2000 using adodbapi 2.0.1 |
| 2 | # Python 2.4.2 and 2.4.3 were used during testing. |
| 3 | from django.db.backends.ado_mssql.base import Cursor |
| 4 | |
| 5 | def get_table_list(cursor): |
| 6 | "Returns a list of table names in the current database." |
| 7 | print "# Note: Any fields that are named 'id', are of type 'AutoField', and" |
| 8 | print "# and are Primary Keys will NOT appear in the model output below." |
| 9 | print "# By default Django assumes that the each model's Primary Key is an " |
| 10 | print "# AutoField with a name of 'id', so there is no need to add it to the" |
| 11 | print "# model description." |
| 12 | print |
| 13 | cursor.execute("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'") |
| 14 | return [row[2] for row in cursor.fetchall()] |
| 15 | |
| 16 | def _is_auto_field(cursor, table_name, column_name): |
| 17 | cursor.execute("SELECT COLUMNPROPERTY( OBJECT_ID('%s'),'%s','IsIdentity')" % (table_name, column_name)) |
| 18 | return cursor.fetchall()[0][0] |
4 | | def get_table_description(cursor, table_name): |
5 | | raise NotImplementedError |
| 20 | def get_table_description(cursor, table_name, identity_check=True): |
| 21 | """Returns a description of the table, with the DB-API cursor.description interface. |
| 22 | |
| 23 | The 'auto_check' parameter has been added to the function argspec. |
| 24 | If set to True, the function will check each of the table's fields for the |
| 25 | IDENTITY property (the IDENTITY property is the MSSQL equivalent to an AutoField). |
| 26 | |
| 27 | When a field is found with an IDENTITY property, it is given a custom field number |
| 28 | of -777, which maps to the 'AutoField' value in the DATA_TYPES_REVERSE dict. |
| 29 | """ |
| 30 | cursor.execute("SELECT TOP 1 * FROM %s" % table_name) |
| 31 | cursor.nextset() |
| 32 | items = [] |
| 33 | if identity_check: |
| 34 | for data in cursor.description: |
| 35 | if _is_auto_field(cursor, table_name, data[0]): |
| 36 | data = list(data) |
| 37 | data[1] = -777 |
| 38 | items.append(list(data)) |
| 39 | else: |
| 40 | items = cursor.description |
| 41 | return items |
| 42 | |
| 43 | def _name_to_index(cursor, table_name): |
| 44 | """ |
| 45 | Returns a dictionary of {field_name: field_index} for the given table. |
| 46 | Indexes are 0-based. |
| 47 | """ |
| 48 | return dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name, identity_check=False))]) |
7 | | def get_relations(cursor, table_name): |
8 | | raise NotImplementedError |
9 | | |
10 | | def get_indexes(cursor, table_name): |
11 | | raise NotImplementedError |
12 | | |
13 | | DATA_TYPES_REVERSE = {} |
| 50 | def get_relations(cursor, table_name): |
| 51 | """ |
| 52 | Returns a dictionary of {field_index: (field_index_other_table, other_table)} |
| 53 | representing all relationships to the given table. Indexes are 0-based. |
| 54 | """ |
| 55 | table_index = _name_to_index(cursor, table_name) |
| 56 | sql = """SELECT e.COLUMN_NAME AS column_name, |
| 57 | c.TABLE_NAME AS referenced_table_name, |
| 58 | d.COLUMN_NAME AS referenced_column_name |
| 59 | FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a |
| 60 | INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS b |
| 61 | ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME |
| 62 | INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE AS c |
| 63 | ON b.UNIQUE_CONSTRAINT_NAME = c.CONSTRAINT_NAME |
| 64 | INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS d |
| 65 | ON c.CONSTRAINT_NAME = d.CONSTRAINT_NAME |
| 66 | INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS e |
| 67 | ON a.CONSTRAINT_NAME = e.CONSTRAINT_NAME |
| 68 | WHERE a.TABLE_NAME = ? AND |
| 69 | a.CONSTRAINT_TYPE = 'FOREIGN KEY'""" |
| 70 | cursor = Cursor(cursor.db.connection) |
| 71 | cursor.execute(sql, (table_name,)) |
| 72 | return dict([(table_index[item[0]], (_name_to_index(cursor, item[1])[item[2]], item[1])) |
| 73 | for item in cursor.fetchall()]) |
| 74 | |
| 75 | def get_indexes(cursor, table_name): |
| 76 | """ |
| 77 | Returns a dictionary of fieldname -> infodict for the given table, |
| 78 | where each infodict is in the format: |
| 79 | {'primary_key': boolean representing whether it's the primary key, |
| 80 | 'unique': boolean representing whether it's a unique index} |
| 81 | """ |
| 82 | sql = """SELECT b.COLUMN_NAME, a.CONSTRAINT_TYPE |
| 83 | FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS a INNER JOIN |
| 84 | INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS b |
| 85 | ON a.CONSTRAINT_NAME = b.CONSTRAINT_NAME AND |
| 86 | a.TABLE_NAME = b.TABLE_NAME |
| 87 | WHERE a.TABLE_NAME = ? AND |
| 88 | (CONSTRAINT_TYPE = 'PRIMARY KEY' OR |
| 89 | CONSTRAINT_TYPE = 'UNIQUE')""" |
| 90 | field_names = [item[0] for item in get_table_description(cursor, table_name, identity_check=False)] |
| 91 | cursor = Cursor(cursor.db.connection) |
| 92 | cursor.execute(sql, (table_name,)) |
| 93 | indexes = {} |
| 94 | results = {} |
| 95 | data = cursor.fetchall() |
| 96 | if data: |
| 97 | results.update(data) |
| 98 | for field in field_names: |
| 99 | val = results.get(field, None) |
| 100 | indexes[field] = dict(primary_key=(val=='PRIMARY KEY'), unique=(val=='UNIQUE')) |
| 101 | return indexes |
| 102 | |
| 103 | # A reference for the values below: |
| 104 | # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ado270/htm/mdcstdatatypeenum.asp |
| 105 | DATA_TYPES_REVERSE = { |
| 106 | # 8192 : Array , |
| 107 | # 128 : Binary , |
| 108 | # 9 : IDispatch , |
| 109 | # 12 : Variant , |
| 110 | # 13 : IUnknown , |
| 111 | # 21 : UnsignedBigInt, |
| 112 | # 132 : UserDefined , |
| 113 | # 0 : Empty , |
| 114 | # 136 : Chapter , |
| 115 | # 138 : PropVariant , |
| 116 | # 204 : VarBinary , |
| 117 | # 205 : LongVarBinary , |
| 118 | -777: 'AutoField', # Custom number used to identify AutoFields |
| 119 | 2 : 'SmallIntegerField', # SmallInt |
| 120 | 3 : 'IntegerField', # Integer |
| 121 | 4 : 'FloatField', # Single |
| 122 | 5 : 'FloatField', # Decimal |
| 123 | 6 : 'FloatField', # Currency |
| 124 | 7 : 'DateField', # Date |
| 125 | 8 : 'CharField', # BSTR |
| 126 | 10 : 'IntegerField', # Error |
| 127 | 11 : 'BooleanField', # Boolean |
| 128 | 14 : 'FloatField', # Decimal |
| 129 | 16 : 'SmallIntegerField', # TinyInt |
| 130 | 17 : 'PositiveSmallIntegerField', # UnsignedTinyInt |
| 131 | 18 : 'PositiveSmallIntegerField', # UnsignedSmallInt |
| 132 | 19 : 'PositiveIntegerField', # UnsignedInt |
| 133 | 20 : 'IntegerField', # BigInt |
| 134 | 64 : 'DateTimeField', # FileTime |
| 135 | 72 : 'CharField', # GUID |
| 136 | 129 : 'CharField', # Char |
| 137 | 130 : 'CharField', # WChar |
| 138 | 131 : 'FloatField', # Numeric |
| 139 | 133 : 'DateField', # DBDate |
| 140 | 134 : 'TimeField', # DBTime |
| 141 | 135 : 'DateTimeField', # DBTimeStamp |
| 142 | 139 : 'FloatField', # VarNumeric |
| 143 | 200 : 'CharField', # VarChar |
| 144 | 201 : 'TextField', # LongVarChar |
| 145 | 202 : 'CharField', # VarWChar |
| 146 | 203 : 'TextField', # LongVarWChar |
| 147 | } |