| 1 |
import re |
|---|
| 2 |
|
|---|
| 3 |
foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") |
|---|
| 4 |
|
|---|
| 5 |
from cx_Oracle import NUMBER, ROWID, LONG_STRING, STRING, FIXED_CHAR, Timestamp, LOB, BLOB, CLOB, BINARY |
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
def get_table_list(cursor): |
|---|
| 9 |
"Returns a list of table names in the current database." |
|---|
| 10 |
cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") |
|---|
| 11 |
return [row[0] for row in cursor.fetchall()] |
|---|
| 12 |
|
|---|
| 13 |
table_description_cache = {} |
|---|
| 14 |
|
|---|
| 15 |
def get_table_description(cursor, table_name): |
|---|
| 16 |
"Returns a description of the table, with the DB-API cursor.description interface." |
|---|
| 17 |
cursor.execute("SELECT * FROM \"%s\" where rownum < 2" % table_name) |
|---|
| 18 |
return cursor.description |
|---|
| 19 |
|
|---|
| 20 |
_name_to_index_cache = {} |
|---|
| 21 |
|
|---|
| 22 |
def _name_to_index(cursor, table_name): |
|---|
| 23 |
""" |
|---|
| 24 |
Returns a dictionary of {field_name: field_index} for the given table. |
|---|
| 25 |
Indexes are 0-based. |
|---|
| 26 |
""" |
|---|
| 27 |
if not _name_to_index_cache.get(table_name): |
|---|
| 28 |
_name_to_index_cache[table_name] = dict([(d[0], i) for i, d in enumerate(get_table_description(cursor, table_name))]) |
|---|
| 29 |
return _name_to_index_cache[table_name] |
|---|
| 30 |
|
|---|
| 31 |
|
|---|
| 32 |
def columnum(cursor, table_name, column_name): |
|---|
| 33 |
res = _name_to_index(cursor,table_name)[column_name] |
|---|
| 34 |
return res |
|---|
| 35 |
|
|---|
| 36 |
def get_relations(cursor, table_name): |
|---|
| 37 |
""" |
|---|
| 38 |
Returns a dictionary of {field_index: (field_index_other_table, other_table)} |
|---|
| 39 |
representing all relationships to the given table. Indexes are 0-based. |
|---|
| 40 |
|
|---|
| 41 |
""" |
|---|
| 42 |
|
|---|
| 43 |
cursor.execute("select col.column_name, con.constraint_type from all_cons_columns col, all_constraints con where col.constraint_name = con.constraint_name and con.constraint_type = 'P' and col.table_name = '%s'" % table_name ) |
|---|
| 44 |
rows = cursor.fetchall() |
|---|
| 45 |
try: |
|---|
| 46 |
primary_key = rows[0][0]; |
|---|
| 47 |
except: |
|---|
| 48 |
primary_key = None |
|---|
| 49 |
|
|---|
| 50 |
|
|---|
| 51 |
res = {} |
|---|
| 52 |
query = """ |
|---|
| 53 |
select col.column_name, col.table_name, col.constraint_name, |
|---|
| 54 |
c2.table_name, c2.column_name |
|---|
| 55 |
from all_cons_columns col, all_constraints con, all_cons_columns c2 |
|---|
| 56 |
where con.constraint_type = 'R' |
|---|
| 57 |
and con.r_constraint_name = c2.constraint_name |
|---|
| 58 |
and con.constraint_name = col.constraint_name |
|---|
| 59 |
and not (col.position = c2.position and |
|---|
| 60 |
col.table_name = c2.table_name) |
|---|
| 61 |
and col.table_name = '%s' |
|---|
| 62 |
""" |
|---|
| 63 |
cursor.execute(query % table_name) |
|---|
| 64 |
relations = {} |
|---|
| 65 |
rows = cursor.fetchall() |
|---|
| 66 |
for row in rows: |
|---|
| 67 |
if row[0] != primary_key: |
|---|
| 68 |
try: |
|---|
| 69 |
relations[columnum(cursor, table_name, row[0])] = ( |
|---|
| 70 |
columnum(cursor,row[3],row[4]), |
|---|
| 71 |
row[3] |
|---|
| 72 |
) |
|---|
| 73 |
except: |
|---|
| 74 |
pass |
|---|
| 75 |
return relations |
|---|
| 76 |
|
|---|
| 77 |
def get_indexes(cursor, table_name): |
|---|
| 78 |
""" |
|---|
| 79 |
Returns a dictionary of fieldname -> infodict for the given table, |
|---|
| 80 |
where each infodict is in the format: |
|---|
| 81 |
{'primary_key': boolean representing whether it's the primary key, |
|---|
| 82 |
'unique': boolean representing whether it's a unique index} |
|---|
| 83 |
""" |
|---|
| 84 |
cursor.execute("select col.column_name, con.constraint_type from all_cons_columns col, all_constraints con where col.constraint_name = con.constraint_name and con.constraint_type in ('P','U') and col.table_name = '%s'" % table_name ) |
|---|
| 85 |
rows = cursor.fetchall() |
|---|
| 86 |
res = {} |
|---|
| 87 |
for r in rows: |
|---|
| 88 |
res[r[0]] = {'primary_key': 0, 'unique': 0} |
|---|
| 89 |
|
|---|
| 90 |
for r in rows: |
|---|
| 91 |
if r[1] == 'P': |
|---|
| 92 |
res[r[0]]['primary_key'] = 1 |
|---|
| 93 |
if r[1] == 'U': |
|---|
| 94 |
res[r[0]]['unique'] = 1 |
|---|
| 95 |
|
|---|
| 96 |
return res |
|---|
| 97 |
|
|---|
| 98 |
# Maps type codes to Django Field types. |
|---|
| 99 |
DATA_TYPES_REVERSE = { |
|---|
| 100 |
NUMBER: 'IntegerField', |
|---|
| 101 |
ROWID: 'IntegerField', |
|---|
| 102 |
LONG_STRING: 'TextField', |
|---|
| 103 |
STRING: 'TextField', |
|---|
| 104 |
FIXED_CHAR: 'CharField', |
|---|
| 105 |
Timestamp: 'DateTimeField', |
|---|
| 106 |
LOB: 'TextField', |
|---|
| 107 |
BLOB: 'TextField', |
|---|
| 108 |
CLOB: 'TextField', |
|---|
| 109 |
BINARY:'TextField', |
|---|
| 110 |
} |
|---|