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