OracleBranch: django-oracle-rev5046.diff
| File django-oracle-rev5046.diff, 83.7 kB (added by bouldersprinters, 1 year ago) |
|---|
-
django/db/backends/mysql/base.py
old new 131 131 self.server_version = tuple([int(x) for x in m.groups()]) 132 132 return self.server_version 133 133 134 allows_group_by_ordinal = True 135 allows_unique_and_pk = True 136 autoindexes_primary_keys = False 137 needs_datetime_string_cast = True # MySQLdb requires a typecast for dates 138 needs_upper_for_iops = False 134 139 supports_constraints = True 140 supports_tablespaces = False 141 uses_case_insensitive_names = False 135 142 136 143 def quote_name(name): 137 144 if name.startswith("`") and name.endswith("`"): … … 164 171 sql = "CAST(DATE_FORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str) 165 172 return sql 166 173 174 def get_datetime_cast_sql(): 175 return None 176 167 177 def get_limit_offset_sql(limit, offset=None): 168 178 sql = "LIMIT " 169 179 if offset and offset != 0: … … 185 195 def get_pk_default_value(): 186 196 return "DEFAULT" 187 197 198 def get_max_name_length(): 199 return 64; 200 201 def get_start_transaction_sql(): 202 return "BEGIN;" 203 204 def get_autoinc_sql(table): 205 return None 206 188 207 def get_sql_flush(style, tables, sequences): 189 208 """Return a list of SQL statements required to remove all data from 190 209 all tables in the database (without actually removing the tables -
django/db/backends/ado_mssql/base.py
old new 88 88 self.connection.close() 89 89 self.connection = None 90 90 91 allows_group_by_ordinal = True 92 allows_unique_and_pk = True 93 autoindexes_primary_keys = True 94 needs_datetime_string_cast = True 95 needs_upper_for_iops = False 91 96 supports_constraints = True 97 supports_tablespaces = True 98 uses_case_insensitive_names = False 92 99 93 100 def quote_name(name): 94 101 if name.startswith('[') and name.endswith(']'): … … 116 123 if lookup_type=='day': 117 124 return "Convert(datetime, Convert(varchar(12), %s))" % field_name 118 125 126 def get_datetime_cast_sql(): 127 return None 128 119 129 def get_limit_offset_sql(limit, offset=None): 120 130 # TODO: This is a guess. Make sure this is correct. 121 131 sql = "LIMIT %s" % limit … … 138 148 def get_pk_default_value(): 139 149 return "DEFAULT" 140 150 151 def get_max_name_length(): 152 return None 153 154 def get_start_transaction_sql(): 155 return "BEGIN;" 156 157 def get_tablespace_sql(tablespace, inline=False): 158 return "ON %s" % quote_name(tablespace) 159 160 def get_autoinc_sql(table): 161 return None 162 141 163 def get_sql_flush(style, tables, sequences): 142 164 """Return a list of SQL statements required to remove all data from 143 165 all tables in the database (without actually removing the tables -
django/db/backends/postgresql/base.py
old new 104 104 self.connection.close() 105 105 self.connection = None 106 106 107 allows_group_by_ordinal = True 108 allows_unique_and_pk = True 109 autoindexes_primary_keys = True 110 needs_datetime_string_cast = True 111 needs_upper_for_iops = False 107 112 supports_constraints = True 113 supports_tablespaces = False 114 uses_case_insensitive_names = False 108 115 109 116 def quote_name(name): 110 117 if name.startswith('"') and name.endswith('"'): … … 137 144 # http://www.postgresql.org/docs/8.0/static/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC 138 145 return "DATE_TRUNC('%s', %s)" % (lookup_type, field_name) 139 146 147 def get_datetime_cast_sql(): 148 return None 149 140 150 def get_limit_offset_sql(limit, offset=None): 141 151 sql = "LIMIT %s" % limit 142 152 if offset and offset != 0: … … 158 168 def get_pk_default_value(): 159 169 return "DEFAULT" 160 170 171 def get_max_name_length(): 172 return None 173 174 def get_start_transaction_sql(): 175 return "BEGIN;" 176 177 def get_autoinc_sql(table): 178 return None 179 161 180 def get_sql_flush(style, tables, sequences): 162 181 """Return a list of SQL statements required to remove all data from 163 182 all tables in the database (without actually removing the tables -
django/db/backends/sqlite3/base.py
old new 99 99 def convert_query(self, query, num_params): 100 100 return query % tuple("?" * num_params) 101 101 102 allows_group_by_ordinal = True 103 allows_unique_and_pk = True 104 autoindexes_primary_keys = True 105 needs_datetime_string_cast = True 106 needs_upper_for_iops = False 102 107 supports_constraints = False 108 supports_tablespaces = False 109 uses_case_insensitive_names = False 103 110 104 111 def quote_name(name): 105 112 if name.startswith('"') and name.endswith('"'): … … 131 138 # sqlite doesn't support DATE_TRUNC, so we fake it as above. 132 139 return 'django_date_trunc("%s", %s)' % (lookup_type.lower(), field_name) 133 140 141 def get_datetime_cast_sql(): 142 return None 143 134 144 def get_limit_offset_sql(limit, offset=None): 135 145 sql = "LIMIT %s" % limit 136 146 if offset and offset != 0: … … 152 162 def get_pk_default_value(): 153 163 return "NULL" 154 164 165 def get_max_name_length(): 166 return None 167 168 def get_start_transaction_sql(): 169 return "BEGIN;" 170 171 def get_autoinc_sql(table): 172 return None 173 155 174 def get_sql_flush(style, tables, sequences): 156 175 """Return a list of SQL statements required to remove all data from 157 176 all tables in the database (without actually removing the tables -
django/db/backends/util.py
old new 1 1 import datetime 2 import md5 2 3 from time import time 3 4 4 5 class CursorDebugWrapper(object): … … 92 93 def rev_typecast_boolean(obj, d): 93 94 return obj and '1' or '0' 94 95 96 def truncate_name(name, length=None): 97 """Shortens a string to a repeatable mangled version with the given length. 98 """ 99 if length is None or len(name) <= length: 100 return name 101 102 hash = md5.md5(name).hexdigest()[:4] 103 104 return '%s%s' % (name[:length-4], hash) 105 95 106 ################################################################################## 96 107 # Helper functions for dictfetch* for databases that don't natively support them # 97 108 ################################################################################## -
django/db/backends/oracle/base.py
old new 4 4 Requires cx_Oracle: http://www.python.net/crew/atuining/cx_Oracle/ 5 5 """ 6 6 7 from django.conf import settings 7 8 from django.db.backends import util 8 9 try: 9 10 import cx_Oracle as Database 10 11 except ImportError, e: 11 12 from django.core.exceptions import ImproperlyConfigured 12 13 raise ImproperlyConfigured, "Error loading cx_Oracle module: %s" % e 14 import datetime 15 from django.utils.datastructures import SortedDict 13 16 17 14 18 DatabaseError = Database.Error 15 19 16 20 try: … … 30 34 return self.connection is not None 31 35 32 36 def cursor(self): 33 from django.conf import settings34 37 if not self._valid_connection(): 35 38 if len(settings.DATABASE_HOST.strip()) == 0: 36 39 settings.DATABASE_HOST = 'localhost' … … 40 43 else: 41 44 conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 42 45 self.connection = Database.connect(conn_string, **self.options) 43 return FormatStylePlaceholderCursor(self.connection) 46 cursor = FormatStylePlaceholderCursor(self.connection) 47 # default arraysize of 1 is highly sub-optimal 48 cursor.arraysize = 100 49 # set oracle date to ansi date format 50 cursor.execute("ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD'") 51 cursor.execute("ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'") 52 if settings.DEBUG: 53 return util.CursorDebugWrapper(cursor, self) 54 return cursor 44 55 45 56 def _commit(self): 46 57 if self.connection is not None: 47 self.connection.commit()58 return self.connection.commit() 48 59 49 60 def _rollback(self): 50 61 if self.connection is not None: 51 try: 52 self.connection.rollback() 53 except Database.NotSupportedError: 54 pass 62 return self.connection.rollback() 55 63 56 64 def close(self): 57 65 if self.connection is not None: 58 66 self.connection.close() 59 67 self.connection = None 60 68 69 allows_group_by_ordinal = False 70 allows_unique_and_pk = False # Suppress UNIQUE/PK for Oracle (ORA-02259) 71 autoindexes_primary_keys = True 72 needs_datetime_string_cast = False 73 needs_upper_for_iops = True 61 74 supports_constraints = True 75 supports_tablespaces = True 76 uses_case_insensitive_names = True 62 77 63 78 class FormatStylePlaceholderCursor(Database.Cursor): 64 79 """ … … 66 81 This fixes it -- but note that if you want to use a literal "%s" in a query, 67 82 you'll need to use "%%s". 68 83 """ 84 def _rewrite_args(self, query, params=None): 85 if params is None: 86 params = [] 87 else: 88 # cx_Oracle can't handle unicode parameters, so cast to str for now 89 for i, param in enumerate(params): 90 if type(param) == unicode: 91 try: 92 params[i] = param.encode('utf-8') 93 except UnicodeError: 94 params[i] = str(param) 95 args = [(':arg%d' % i) for i in range(len(params))] 96 query = query % tuple(args) 97 # cx_Oracle cannot execute a query with the closing ';' 98 if query.endswith(';'): 99 query = query[:-1] 100 return query, params 101 69 102 def execute(self, query, params=None): 70 if params is None: params = [] 71 query = self.convert_arguments(query, len(params)) 103 query, params = self._rewrite_args(query, params) 72 104 return Database.Cursor.execute(self, query, params) 73 105 74 106 def executemany(self, query, params=None): 75 if params is None: params = [] 76 query = self.convert_arguments(query, len(params[0])) 107 query, params = self._rewrite_args(query, params) 77 108 return Database.Cursor.executemany(self, query, params) 78 109 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)83 84 110 def quote_name(name): 85 return name 111 # SQL92 requires delimited (quoted) names to be case-sensitive. When 112 # not quoted, Oracle has case-insensitive behavior for identifiers, but 113 # always defaults to uppercase. 114 # We simplify things by making Oracle identifiers always uppercase. 115 if not name.startswith('"') and not name.endswith('"'): 116 name = '"%s"' % util.truncate_name(name.upper(), get_max_name_length()) 117 return name.upper() 86 118 87 119 dictfetchone = util.dictfetchone 88 120 dictfetchmany = util.dictfetchmany 89 121 dictfetchall = util.dictfetchall 90 122 91 123 def get_last_insert_id(cursor, table_name, pk_name): 92 query = "SELECT %s_sq.currval from dual" % table_name93 cursor.execute( query)124 sq_name = util.truncate_name(table_name, get_max_name_length()-3) 125 cursor.execute('SELECT %s_sq.currval FROM dual' % sq_name) 94 126 return cursor.fetchone()[0] 95 127 96 128 def get_date_extract_sql(lookup_type, table_name): 97 129 # lookup_type is 'year', 'month', 'day' 98 # http:// www.psoug.org/reference/date_func.html130 # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions42a.htm#1017163 99 131 return "EXTRACT(%s FROM %s)" % (lookup_type, table_name) 100 132 101 133 def get_date_trunc_sql(lookup_type, field_name): 102 return "EXTRACT(%s FROM TRUNC(%s))" % (lookup_type, field_name) 134 # lookup_type is 'year', 'month', 'day' 135 # Oracle uses TRUNC() for both dates and numbers. 136 # http://download-east.oracle.com/docs/cd/B10501_01/server.920/a96540/functions155a.htm#SQLRF06151 137 if lookup_type == 'day': 138 sql = 'TRUNC(%s)' % (field_name,) 139 else: 140 sql = "TRUNC(%s, '%s')" % (field_name, lookup_type) 141 return sql 103 142 143 def get_datetime_cast_sql(): 144 return "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS')" 145 104 146 def get_limit_offset_sql(limit, offset=None): 105 147 # Limits and offset are too complicated to be handled here. 106 # Instead, they are handled in django/db/ query.py.107 pass148 # Instead, they are handled in django/db/backends/oracle/query.py. 149 return "" 108 150 109 151 def get_random_function_sql(): 110 152 return "DBMS_RANDOM.RANDOM" … … 116 158 raise NotImplementedError 117 159 118 160 def get_drop_foreignkey_sql(): 119 return "DROP FOREIGN KEY"161 return "DROP CONSTRAINT" 120 162 121 163 def get_pk_default_value(): 122 164 return "DEFAULT" 123 165 166 def get_max_name_length(): 167 return 30 168 169 def get_start_transaction_sql(): 170 return None 171 172 def get_tablespace_sql(tablespace, inline=False): 173 return "%sTABLESPACE %s" % ((inline and "USING INDEX " or ""), quote_name(tablespace)) 174 175 def get_autoinc_sql(table): 176 # To simulate auto-incrementing primary keys in Oracle, we have to 177 # create a sequence and a trigger. 178 sq_name = get_sequence_name(table) 179 tr_name = get_trigger_name(table) 180 sequence_sql = 'CREATE SEQUENCE %s;' % sq_name 181 trigger_sql = """CREATE OR REPLACE TRIGGER %s 182 BEFORE INSERT ON %s 183 FOR EACH ROW 184 WHEN (new.id IS NULL) 185 BEGIN 186 SELECT %s.nextval INTO :new.id FROM dual; 187 END;\n""" % (tr_name, quote_name(table), sq_name) 188 return sequence_sql, trigger_sql 189 190 def get_drop_sequence(table): 191 return "DROP SEQUENCE %s;" % quote_name(get_sequence_name(table)) 192 193 def _get_sequence_reset_sql(): 194 # TODO: colorize this SQL code with style.SQL_KEYWORD(), etc. 195 return """ 196 DECLARE 197 startvalue integer; 198 cval integer; 199 BEGIN 200 LOCK TABLE %(table)s IN SHARE MODE; 201 SELECT NVL(MAX(id), 0) INTO startvalue FROM %(table)s; 202 SELECT %(sequence)s.nextval INTO cval FROM dual; 203 cval := startvalue - cval; 204 IF cval != 0 THEN 205 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s MINVALUE 0 INCREMENT BY '||cval; 206 SELECT %(sequence)s.nextval INTO cval FROM dual; 207 EXECUTE IMMEDIATE 'ALTER SEQUENCE %(sequence)s INCREMENT BY 1'; 208 END IF; 209 COMMIT; 210 END;\n""" 211 124 212 def get_sql_flush(style, tables, sequences): 125 213 """Return a list of SQL statements required to remove all data from 126 214 all tables in the database (without actually removing the tables 127 215 themselves) and put the database in an empty 'initial' state 128 216 """ 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 132 sql = ['%s %s;' % \ 133 (style.SQL_KEYWORD('TRUNCATE'), 217 # Return a list of 'TRUNCATE x;', 'TRUNCATE y;', 218 # 'TRUNCATE z;'... style SQL statements 219 if tables: 220 # Oracle does support TRUNCATE, but it seems to get us into 221 # FK referential trouble, whereas DELETE FROM table works. 222 sql = ['%s %s %s;' % \ 223 (style.SQL_KEYWORD('DELETE'), 224 style.SQL_KEYWORD('FROM'), 134 225 style.SQL_FIELD(quote_name(table)) 135 226 ) for table in tables] 227 # Since we've just deleted all the rows, running our sequence 228 # ALTER code will reset the sequence to 0. 229 for sequence_info in sequences: 230 table_name = sequence_info['table'] 231 seq_name = get_sequence_name(table_name) 232 query = _get_sequence_reset_sql() % {'sequence':seq_name, 233 'table':quote_name(table_name)} 234 sql.append(query) 235 return sql 236 else: 237 return [] 136 238 239 def get_sequence_name(table): 240 name_length = get_max_name_length() - 3 241 return '%s_SQ' % util.truncate_name(table, name_length).upper() 242 137 243 def get_sql_sequence_reset(style, model_list): 138 244 "Returns a list of the SQL statements to reset sequences for the given models." 139 # No sequence reset required 140 return [] 245 from django.db import models 246 output = [] 247 query = _get_sequence_reset_sql() 248 for model in model_list: 249 for f in model._meta.fields: 250 if isinstance(f, models.AutoField): 251 sequence_name = get_sequence_name(model._meta.db_table) 252 output.append(query % {'sequence':sequence_name, 253 'table':model._meta.db_table}) 254 break # Only one AutoField is allowed per model, so don't bother continuing. 255 for f in model._meta.many_to_many: 256 sequence_name = get_sequence_name(f.m2m_db_table()) 257 output.append(query % {'sequence':sequence_name, 258 'table':f.m2m_db_table()}) 259 return output 141 260 261 def get_trigger_name(table): 262 name_length = get_max_name_length() - 3 263 return '%s_TR' % util.truncate_name(table, name_length).upper() 264 265 def get_query_set_class(DefaultQuerySet): 266 "Create a custom QuerySet class for Oracle." 267 268 from django.db import backend, connection 269 from django.db.models.query import EmptyResultSet, GET_ITERATOR_CHUNK_SIZE 270 271 class OracleQuerySet(DefaultQuerySet): 272 273 def iterator(self): 274 "Performs the SELECT database lookup of this QuerySet." 275 276 from django.db.models.query import get_cached_row 277 278 # self._select is a dictionary, and dictionaries' key order is 279 # undefined, so we convert it to a list of tuples. 280 extra_select = self._select.items() 281 282 full_query = None 283 284 try: 285 try: 286 select, sql, params, full_query = self._get_sql_clause(get_full_query=True) 287 except TypeError: 288 select, sql, params = self._get_sql_clause() 289 except EmptyResultSet: 290 raise StopIteration 291 if not full_query: 292 full_query = "SELECT %s%s\n%s" % \ 293 ((self._distinct and "DISTINCT " or ""), 294 ', '.join(select), sql) 295 296 cursor = connection.cursor() 297 cursor.execute(full_query, params) 298 299 fill_cache = self._select_related 300 fields = self.model._meta.fields 301 index_end = len(fields) 302 303 # so here's the logic; 304 # 1. retrieve each row in turn 305 # 2. convert NCLOBs 306 307 while 1: 308 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 309 if not rows: 310 raise StopIteration 311 for row in rows: 312 row = self.resolve_columns(row, fields) 313 if fill_cache: 314 obj, index_end = get_cached_row(klass=self.model, row=row, 315 index_start=0, max_depth=self._max_related_depth) 316 else: 317 obj = self.model(*row[:index_end]) 318 for i, k in enumerate(extra_select): 319 setattr(obj, k[0], row[index_end+i]) 320 yield obj 321 322 323 def _get_sql_clause(self, get_full_query=False): 324 from django.db.models.query import fill_table_cache, \ 325 handle_legacy_orderlist, orderfield2column 326 327 opts = self.model._meta 328 329 # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 330 select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] 331 tables = [quote_only_if_word(t) for t in self._tables] 332 joins = SortedDict() 333 where = self._where[:] 334 params = self._params[:] 335 336 # Convert self._filters into SQL. 337 joins2, where2, params2 = self._filters.get_sql(opts) 338 joins.update(joins2) 339 where.extend(where2) 340 params.extend(params2) 341 342 # Add additional tables and WHERE clauses based on select_related. 343 if self._select_related: 344 fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 345 346 # Add any additional SELECTs. 347 if self._select: 348 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) 349 350 # Start composing the body of the SQL statement. 351 sql = [" FROM", backend.quote_name(opts.db_table)] 352 353 # Compose the join dictionary into SQL describing the joins. 354 if joins: 355 sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 356 for (alias, (table, join_type, condition)) in joins.items()])) 357 358 # Compose the tables clause into SQL. 359 if tables: 360 sql.append(", " + ", ".join(tables)) 361 362 # Compose the where clause into SQL. 363 if where: 364 sql.append(where and "WHERE " + " AND ".join(where)) 365 366 # ORDER BY clause 367 order_by = [] 368 if self._order_by is not None: 369 ordering_to_use = self._order_by 370 else: 371 ordering_to_use = opts.ordering 372 for f in handle_legacy_orderlist(ordering_to_use): 373 if f == '?': # Special case. 374 order_by.append(backend.get_random_function_sql()) 375 else: 376 if f.startswith('-'): 377 col_name = f[1:] 378 order = "DESC" 379 else: 380 col_name = f 381 order = "ASC" 382 if "." in col_name: 383 table_prefix, col_name = col_name.split('.', 1) 384 table_prefix = backend.quote_name(table_prefix) + '.' 385 else: 386 # Use the database table as a column prefix if it wasn't given, 387 # and if the requested column isn't a custom SELECT. 388 if "." not in col_name and col_name not in (self._select or ()): 389 table_prefix = backend.quote_name(opts.db_table) + '.' 390 else: 391 table_prefix = '' 392 order_by.append('%s%s %s' % (table_prefix, backend.quote_name(orderfield2column(col_name, opts)), order)) 393 if order_by: 394 sql.append("ORDER BY " + ", ".join(order_by)) 395 396 # Look for column name collisions in the select elements 397 # and fix them with an AS alias. This allows us to do a 398 # SELECT * later in the paging query. 399 cols = [clause.split('.')[-1] for clause in select] 400 for index, col in enumerate(cols): 401 if cols.count(col) > 1: 402 col = '%s%d' % (col.replace('"', ''), index) 403 cols[index] = col 404 select[index] = '%s AS %s' % (select[index], col) 405 406 # LIMIT and OFFSET clauses 407 # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 408 select_clause = ",".join(select) 409 distinct = (self._distinct and "DISTINCT " or "") 410 411 if order_by: 412 order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by)) 413 else: 414 #Oracle's row_number() function always requires an order-by clause. 415 #So we need to define a default order-by, since none was provided. 416 order_by_clause = " OVER (ORDER BY %s.%s)" % \ 417 (backend.quote_name(opts.db_table), 418 backend.quote_name(opts.fields[0].db_column or opts.fields[0].column)) 419 # limit_and_offset_clause 420 if self._limit is None: 421 assert self._offset is None, "'offset' is not allowed without 'limit'" 422 423 if self._offset is not None: 424 offset = int(self._offset) 425 else: 426 offset = 0 427 if self._limit is not None: 428 limit = int(self._limit) 429 else: 430 limit = None 431 432 limit_and_offset_clause = '' 433 if limit is not None: 434 limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 435 elif offset: 436 limit_and_offset_clause = "WHERE rn > %s" % (offset) 437 438 if len(limit_and_offset_clause) > 0: 439 fmt = \ 440 """SELECT * FROM 441 (SELECT %s%s, 442 ROW_NUMBER()%s AS rn 443 %s) 444 %s""" 445 full_query = fmt % (distinct, select_clause, 446 order_by_clause, ' '.join(sql).strip(), 447 limit_and_offset_clause) 448 else: 449 full_query = None 450 451 if get_full_query: 452 return select, " ".join(sql), params, full_query 453 else: 454 return select, " ".join(sql), params 455 456 def resolve_columns(self, row, fields=()): 457 from django.db.models.fields import DateField, DateTimeField, \ 458 TimeField, BooleanField, NullBooleanField 459 values = [] 460 for value, field in map(None, row, fields): 461 if isinstance(value, Database.LOB): 462 value = value.read() 463 # Since Oracle won't distinguish between NULL and an empty 464 # string (''), we store empty strings as a space. Here is 465 # where we undo that treachery. 466 if value == ' ': 467 value = '' 468 # Convert 1 or 0 to True or False 469 elif value in (1, 0) and isinstance(field, (BooleanField, NullBooleanField)): 470 value = bool(value) 471 # cx_Oracle always returns datetime.datetime objects for 472 # DATE and TIMESTAMP columns, but Django wants to see a 473 # python datetime.date, .time, or .datetime. We use the type 474 # of the Field to determine which to cast to, but it's not 475 # always available. 476 # As a workaround, we cast to date if all the time-related 477 # values are 0, or to time if the date is 1/1/1900. 478 # This could be cleaned a bit by adding a method to the Field 479 # classes to normalize values from the database (the to_python 480 # method is used for validation and isn't what we want here). 481 elif isinstance(value, Database.Timestamp): 482 # In Python 2.3, the cx_Oracle driver returns its own 483 # Timestamp object that we must convert to a datetime class. 484 if not isinstance(value, datetime.datetime): 485 value = datetime.datetime(value.year, value.month, value.day, value.hour, 486 value.minute, value.second, value.fsecond) 487 if isinstance(field, DateTimeField): 488 pass # DateTimeField subclasses DateField so must be checked first. 489 elif isinstance(field, DateField): 490 value = value.date() 491 elif isinstance(field, TimeField) or (value.year == 1900 and value.month == value.day == 1): 492 value = value.time() 493 elif value.hour == value.minute == value.second == value.microsecond == 0: 494 value = value.date() 495 values.append(value) 496 return values 497 498 return OracleQuerySet 499 500 142 501 OPERATOR_MAPPING = { 143 502 'exact': '= %s', 144 'iexact': ' LIKE %s',145 'contains': 'LIKE %s',146 'icontains': 'LIKE %s',503 'iexact': '= UPPER(%s)', 504 'contains': "LIKE %s ESCAPE '\\'", 505 'icontains': "LIKE UPPER(%s) ESCAPE '\\'", 147 506 'gt': '> %s', 148 507 'gte': '>= %s', 149 508 'lt': '< %s', 150 509 'lte': '<= %s', 151 'startswith': 'LIKE %s',152 'endswith': 'LIKE %s',153 'istartswith': 'LIKE %s',154 'iendswith': 'LIKE %s',510 'startswith': "LIKE %s ESCAPE '\\'", 511 'endswith': "LIKE %s ESCAPE '\\'", 512 'istartswith': "LIKE UPPER(%s) ESCAPE '\\'", 513 'iendswith': "LIKE UPPER(%s) ESCAPE '\\'", 155 514 } -
django/db/backends/oracle/client.py
old new 2 2 import os 3 3 4 4 def runshell(): 5 args = '' 6 args += settings.DATABASE_USER 5 dsn = settings.DATABASE_USER 7 6 if settings.DATABASE_PASSWORD: 8 args += "/%s" % settings.DATABASE_PASSWORD 9 args += "@%s" % settings.DATABASE_NAME 10 os.execvp('sqlplus', args) 7 dsn += "/%s" % settings.DATABASE_PASSWORD 8 if settings.DATABASE_NAME: 9 dsn += "@%s" % settings.DATABASE_NAME 10 args = ["sqlplus", "-L", dsn] 11 os.execvp("sqlplus", args) -
django/db/backends/oracle/introspection.py
old new 1 from django.db.backends.oracle.base import quote_name 1 2 import re 3 import cx_Oracle 2 4 5 3 6 foreign_key_re = re.compile(r"\sCONSTRAINT `[^`]*` FOREIGN KEY \(`([^`]*)`\) REFERENCES `([^`]*)` \(`([^`]*)`\)") 4 7 5 8 def get_table_list(cursor): 6 9 "Returns a list of table names in the current database." 7 10 cursor.execute("SELECT TABLE_NAME FROM USER_TABLES") 8 return [row[0] for row in cursor.fetchall()]11 return [row[0].upper() for row in cursor.fetchall()] 9 12 10 13 def get_table_description(cursor, table_name): 11 return table_name 14 "Returns a description of the table, with the DB-API cursor.description interface." 15 cursor.execute("SELECT * FROM %s WHERE ROWNUM < 2" % quote_name(table_name)) 16 return cursor.description 12 17 13 18 def _name_to_index(cursor, table_name): 14 19 """ … … 22 27 Returns a dictionary of {field_index: (field_index_other_table, other_table)} 23 28 representing all relationships to the given table. Indexes are 0-based. 24 29 """ 25 raise NotImplementedError 30 cursor.execute(""" 31 SELECT ta.column_id - 1, tb.table_name, tb.column_id - 1 32 FROM user_constraints, USER_CONS_COLUMNS ca, USER_CONS_COLUMNS cb, 33 user_tab_cols ta, user_tab_cols tb 34 WHERE user_constraints.table_name = %s AND 35 ta.table_name = %s AND 36 ta.column_name = ca.column_name AND 37 ca.table_name = %s AND 38 user_constraints.constraint_name = ca.constraint_name AND 39 user_constraints.r_constraint_name = cb.constraint_name AND 40 cb.table_name = tb.table_name AND 41 cb.column_name = tb.column_name AND 42 ca.position = cb.position""", [table_name, table_name, table_name]) 26 43 44 relations = {} 45 for row in cursor.fetchall(): 46 relations[row[0]] = (row[2], row[1]) 47 return relations 48 27 49 def get_indexes(cursor, table_name): 28 50 """ 29 51 Returns a dictionary of fieldname -> infodict for the given table, … … 31 53 {'primary_key': boolean representing whether it's the primary key, 32 54 'unique': boolean representing whether it's a unique index} 33 55 """ 34 raise NotImplementedError 56 # This query retrieves each index on the given table, including the 57 # first associated field name 58 # "We were in the nick of time; you were in great peril!" 59 sql = """ 60 WITH primarycols AS ( 61 SELECT user_cons_columns.table_name, user_cons_columns.column_name, 1 AS PRIMARYCOL 62 FROM user_cons_columns, user_constraints 63 WHERE user_cons_columns.constraint_name = user_constraints.constraint_name AND 64 user_constraints.constraint_type = 'P' AND 65 user_cons_columns.table_name = %s), 66 uniquecols AS ( 67 SELECT user_ind_columns.table_name, user_ind_columns.column_name, 1 AS UNIQUECOL 68 FROM user_indexes, user_ind_columns 69 WHERE uniqueness = 'UNIQUE' AND 70 user_indexes.index_name = user_ind_columns.index_name AND 71 user_ind_columns.table_name = %s) 72 SELECT allcols.column_name, primarycols.primarycol, uniquecols.UNIQUECOL 73 FROM (SELECT column_name FROM primarycols UNION SELECT column_name FROM 74 uniquecols) allcols, 75 primarycols, uniquecols 76 WHERE allcols.column_name = primarycols.column_name (+) AND 77 allcols.column_name = uniquecols.column_name (+) 78 """ 79 cursor.execute(sql, [table_name, table_name]) 80 indexes = {} 81 for row in cursor.fetchall(): 82 # row[1] (idx.indkey) is stored in the DB as an array. It comes out as 83 # a string of space-separated integers. This designates the field 84 # indexes (1-based) of the fields that have indexes on the table. 85 # Here, we skip any indexes across multiple fields. 86 indexes[row[0]] = {'primary_key': row[1], 'unique': row[2]} 87 return indexes 35 88 36 # Maps type codes to Django Field types.89 # Maps type objects to Django Field types. 37 90 DATA_TYPES_REVERSE = { 38 16: 'BooleanField', 39 21: 'SmallIntegerField', 40 23: 'IntegerField', 41 25: 'TextField', 42 869: 'IPAddressField', 43 1043: 'CharField', 44 1082: 'DateField', 45 1083: 'TimeField', 46 1114: 'DateTimeField', 47 1184: 'DateTimeField', 48 1266: 'TimeField', 49 1700: 'FloatField', 91 cx_Oracle.CLOB: 'TextField', 92 cx_Oracle.DATETIME: 'DateTimeField', 93 cx_Oracle.FIXED_CHAR: 'CharField', 94 cx_Oracle.NCLOB: 'TextField', 95 cx_Oracle.NUMBER: 'FloatField', 96 cx_Oracle.STRING: 'TextField', 97 cx_Oracle.TIMESTAMP: 'DateTimeField', 50 98 } -
django/db/backends/oracle/creation.py
old new 1 import sys, time 2 from django.core import management 3 4 # This dictionary maps Field objects to their associated Oracle column 5 # types, as strings. Column-type strings can contain format strings; they'll 6 # be interpolated against the values of Field.__dict__ before being output. 7 # If a column type is set to None, it won't be included in the output. 1 8 DATA_TYPES = { 2 'AutoField': 'number(38)',3 'BooleanField': 'number(1)',4 'CharField': 'varchar2(%(maxlength)s)',5 'CommaSeparatedIntegerField': 'varchar2(%(maxlength)s)',6 'DateField': 'date',7 'DateTimeField': 'date',8 'FileField': 'varchar2(100)',9 'FilePathField': 'varchar2(100)',10 'FloatField': 'number(%(max_digits)s, %(decimal_places)s)',11 'ImageField': 'varchar2(100)',12 'IntegerField': 'integer',13 'IPAddressField': 'char(15)',9 'AutoField': 'NUMBER(11)', 10 'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))', 11 'CharField': 'VARCHAR2(%(maxlength)s)', 12 'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)', 13 'DateField': 'DATE', 14 'DateTimeField': 'TIMESTAMP', 15 'FileField': 'VARCHAR2(100)', 16 'FilePathField': 'VARCHAR2(100)', 17 'FloatField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', 18 'ImageField': 'VARCHAR2(100)', 19 'IntegerField': 'NUMBER(11)', 20 'IPAddressField': 'VARCHAR2(15)', 14 21 'ManyToManyField': None, 15 'NullBooleanField': 'integer', 16 'OneToOneField': 'integer', 17 'PhoneNumberField': 'varchar(20)', 18 'PositiveIntegerField': 'integer', 19 'PositiveSmallIntegerField': 'smallint', 20 'SlugField': 'varchar(50)', 21 'SmallIntegerField': 'smallint', 22 'TextField': 'long', 23 'TimeField': 'timestamp', 24 'USStateField': 'varchar(2)', 22 'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', 23 'OneToOneField': 'NUMBER(11)', 24 'PhoneNumberField': 'VARCHAR2(20)', 25 'PositiveIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)', 26 'PositiveSmallIntegerField': 'NUMBER(11) CHECK (%(column)s >= 0)', 27 'SlugField': 'VARCHAR2(50)', 28 'SmallIntegerField': 'NUMBER(11)', 29 'TextField': 'NCLOB', 30 'TimeField': 'TIMESTAMP', 31 'URLField': 'VARCHAR2(200)', 32 'USStateField': 'CHAR(2)', 25 33 } 34 35 TEST_DATABASE_PREFIX = 'test_' 36 PASSWORD = 'Im_a_lumberjack' 37 REMEMBER = {} 38 39 40 def create_test_db(settings, connection, backend, verbosity=1, autoclobber=False): 41 42 TEST_DATABASE_NAME = _test_database_name(settings) 43 TEST_DATABASE_USER = _test_database_user(settings) 44 TEST_DATABASE_PASSWD = _test_database_passwd(settings) 45 TEST_DATABASE_TBLSPACE = _test_database_tblspace(settings) 46 TEST_DATABASE_TBLSPACE_TMP = _test_database_tblspace_tmp(settings) 47 48 parameters = { 49 'dbname': TEST_DATABASE_NAME, 50 'user': TEST_DATABASE_USER, 51 &nbs
