Django

Code

OracleBranch: introspection_without_debug.py

File introspection_without_debug.py, 3.7 kB (added by Marc Mengel <mengel@fnal.gov>, 2 years ago)

Improved database introspection code for Oracle which does primary keys, foreign keys, etc.

Line 
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 }