2 Oracle database backend for Django.
4 Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/
7 from django
.db
.backends
import util
9 import cx_Oracle
as Database
10 except ImportError, e
:
11 from django
.core
.exceptions
import ImproperlyConfigured
12 raise ImproperlyConfigured
, "Error loading cx_Oracle module: %s" % e
14 DatabaseError
= Database
.Error
17 # Only exists in Python 2.4+
18 from threading
import local
20 # Import copy of _thread_local.py from Python 2.4
21 from django
.utils
._threading
_local
import local
23 class DatabaseWrapper(local
):
24 def __init__(self
, **kwargs
):
25 self
.connection
= None
29 def _valid_connection(self
):
30 return self
.connection
is not None
33 from django
.conf
import settings
34 if not self
._valid
_connection
():
35 if len(settings
.DATABASE_HOST
.strip()) == 0:
36 settings
.DATABASE_HOST
= 'localhost'
37 if len(settings
.DATABASE_PORT
.strip()) != 0:
38 dsn
= Database
.makedsn(settings
.DATABASE_HOST
, int(settings
.DATABASE_PORT
), settings
.DATABASE_NAME
)
39 self
.connection
= Database
.connect(settings
.DATABASE_USER
, settings
.DATABASE_PASSWORD
, dsn
, **self
.options
)
41 conn_string
= "%s/%s@%s" % (settings
.DATABASE_USER
, settings
.DATABASE_PASSWORD
, settings
.DATABASE_NAME
)
42 self
.connection
= Database
.connect(conn_string
, **self
.options
)
43 return FormatStylePlaceholderCursor(self
.connection
)
46 if self
.connection
is not None:
47 self
.connection
.commit()
50 if self
.connection
is not None:
52 self
.connection
.rollback()
53 except Database
.NotSupportedError
:
57 if self
.connection
is not None:
58 self
.connection
.close()
59 self
.connection
= None
61 supports_constraints
= True
63 class FormatStylePlaceholderCursor(Database
.Cursor
):
65 Django uses "format" (e.g. '%s') style placeholders, but Oracle uses ":var" style.
66 This fixes it -- but note that if you want to use a literal "%s" in a query,
67 you'll need to use "%%s".
69 def execute(self
, query
, params
=None):
70 if params
is None: params
= []
71 query
= self
.convert_arguments(query
, len(params
))
72 return Database
.Cursor
.execute(self
, query
, params
)
74 def executemany(self
, query
, params
=None):
75 if params
is None: params
= []
76 query
= self
.convert_arguments(query
, len(params
[0]))
77 return Database
.Cursor
.executemany(self
, query
, params
)
79 def convert_arguments(self
, query
, num_params
):
80 # replace occurances of "%s" with ":arg" - Oracle requires colons for parameter placeholders.
81 args
= [':arg' for i
in range(num_params
)]
82 return query
% tuple(args
)
87 dictfetchone
= util
.dictfetchone
88 dictfetchmany
= util
.dictfetchmany
89 dictfetchall
= util
.dictfetchall
91 def get_last_insert_id(cursor
, table_name
, pk_name
):
92 query
= "SELECT %s_sq.currval from dual" % table_name
94 return cursor
.fetchone()[0]
96 def get_date_extract_sql(lookup_type
, table_name
):
97 # lookup_type is 'year', 'month', 'day'
98 # http://www.psoug.org/reference/date_func.html
99 return "EXTRACT(%s FROM %s)" % (lookup_type
, table_name
)
101 def get_date_trunc_sql(lookup_type
, field_name
):
102 return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type
, field_name
)
104 def get_limit_offset_sql(limit
, offset
=None):
105 # Limits and offset are too complicated to be handled here.
106 # Instead, they are handled in django/db/query.py.
109 def get_random_function_sql():
110 return "DBMS_RANDOM.RANDOM"
112 def get_deferrable_sql():
113 return " DEFERRABLE INITIALLY DEFERRED"
115 def get_fulltext_search_sql(field_name
):
116 raise NotImplementedError
118 def get_drop_foreignkey_sql():
119 return "DROP FOREIGN KEY"
121 def get_pk_default_value():
124 def get_sql_flush(style
, tables
, sequences
):
125 """Return a list of SQL statements required to remove all data from
126 all tables in the database (without actually removing the tables
127 themselves) and put the database in an empty 'initial' state
129 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 'TRUNCATE z;'... style SQL statements
130 # TODO - SQL not actually tested against Oracle yet!
131 # TODO - autoincrement indices reset required? See other get_sql_flush() implementations
133 (style
.SQL_KEYWORD('TRUNCATE'),
134 style
.SQL_FIELD(quote_name(table
))
135 ) for table
in tables
]
141 'contains': 'LIKE %s',
142 'icontains': 'LIKE %s',
147 'startswith': 'LIKE %s',
148 'endswith': 'LIKE %s',
149 'istartswith': 'LIKE %s',
150 'iendswith': 'LIKE %s',