Ticket #1990: django_oracle_rev3496.patch
File django_oracle_rev3496.patch, 15.8 KB (added by , 18 years ago) |
---|
-
db/models/base.py
171 171 record_exists = True 172 172 if pk_set: 173 173 # Determine whether a record with the primary key already exists. 174 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \ 175 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val]) 174 lim = settings.DATABASE_ENGINE != 'oracle' and ' LIMIT 1' or '' 175 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s %s" % \ 176 (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), lim), [pk_val]) 176 177 # If it does already exist, do an UPDATE. 177 178 if cursor.fetchone(): 178 179 db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks] -
db/models/fields/__init__.py
158 158 159 159 def get_db_prep_save(self, value): 160 160 "Returns field's value prepared for saving into a database." 161 # Oracle treats empty strings ('') the same as NULLs. 162 # To get around this wart, we need to change it to something else... 163 if settings.DATABASE_ENGINE == 'oracle' and value == '': 164 value = ' ' 161 165 return value 162 166 163 167 def get_db_prep_lookup(self, lookup_type, value): … … 446 450 def get_db_prep_save(self, value): 447 451 # Casts dates into string format for entry into database. 448 452 if value is not None: 449 value = value.strftime('%Y-%m-%d') 453 if settings.DATABASE_ENGINE != 'oracle': 454 #Oracle does not need a string conversion 455 value = value.strftime('%Y-%m-%d') 450 456 return Field.get_db_prep_save(self, value) 451 457 452 458 def get_manipulator_field_objs(self): … … 744 750 # doesn't support microseconds. 745 751 if settings.DATABASE_ENGINE == 'mysql': 746 752 value = value.replace(microsecond=0) 747 value = str(value) 753 value = str(value) 754 elif settings.DATABASE_ENGINE == 'oracle': 755 value = value.replace(microsecond=0) 756 else: 757 value = str(value) 748 758 return Field.get_db_prep_save(self, value) 749 759 750 760 def get_manipulator_field_objs(self): -
db/models/query.py
3 3 from django.db.models import signals 4 4 from django.dispatch import dispatcher 5 5 from django.utils.datastructures import SortedDict 6 from django.conf import settings 6 7 import operator 7 8 import re 8 9 … … 168 169 extra_select = self._select.items() 169 170 170 171 cursor = connection.cursor() 171 select, sql, params = self._get_sql_clause() 172 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 172 select, sql, params, full_query = self._get_sql_clause() 173 174 if not full_query: 175 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 176 else: 177 cursor.execute(full_query, params) 173 178 fill_cache = self._select_related 174 179 index_end = len(self.model._meta.fields) 175 180 while 1: … … 192 197 counter._offset = None 193 198 counter._limit = None 194 199 counter._select_related = False 195 select, sql, params = counter._get_sql_clause()200 select, sql, params, full_query = counter._get_sql_clause() 196 201 cursor = connection.cursor() 197 202 if self._distinct: 198 203 id_col = "%s.%s" % (backend.quote_name(self.model._meta.db_table), … … 501 506 sql.append("ORDER BY " + ", ".join(order_by)) 502 507 503 508 # LIMIT and OFFSET clauses 504 if self._limit is not None: 505 sql.append("%s " % backend.get_limit_offset_sql(self._limit, self._offset)) 509 if (settings.DATABASE_ENGINE != 'oracle'): 510 if self._limit is not None: 511 sql.append("%s " % backend.get_limit_offset_sql(self._limit, self._offset)) 512 else: 513 assert self._offset is None, "'offset' is not allowed without 'limit'" 514 515 return select, " ".join(sql), params 506 516 else: 507 assert self._offset is None, "'offset' is not allowed without 'limit'" 517 # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 518 select_clause = ",".join(select) 519 distinct = (self._distinct and "DISTINCT " or "") 508 520 509 return select, " ".join(sql), params 521 if order_by: 522 order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by)) 523 else: 524 #Oracle's row_number() function always requires an order-by clause. 525 #So we need to define a default order-by, since none was provided. 526 order_by_clause = " OVER (ORDER BY %s.%s)" % \ 527 (backend.quote_name(opts.db_table), 528 backend.quote_name(opts.fields[0].db_column or opts.fields[0].column)) 529 # limit_and_offset_clause 530 offset = self._offset and int(self._offset) or 0 531 limit = self._limit and int(self._limit) or None 532 limit_and_offset_clause = '' 533 if limit: 534 limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 535 else offset: 536 limit_and_offset_clause = "WHERE rn > %s" % (offset) 510 537 538 if len(limit_and_offset_clause) > 0: 539 full_query = """SELECT * FROM 540 (SELECT %s 541 %s, 542 ROW_NUMBER() %s AS rn 543 %s 544 ) 545 %s 546 """ % (distinct, select_clause, order_by_clause, " ".join(sql), limit_and_offset_clause) 547 else: 548 full_query = None 549 550 return select, " ".join(sql), params, full_query 511 551 class ValuesQuerySet(QuerySet): 512 552 def iterator(self): 513 553 # select_related and select aren't supported in values(). … … 523 563 field_names = [f.attname for f in self.model._meta.fields] 524 564 525 565 cursor = connection.cursor() 526 select, sql, params = self._get_sql_clause()566 select, sql, params, full_query = self._get_sql_clause() 527 567 select = ['%s.%s' % (backend.quote_name(self.model._meta.db_table), backend.quote_name(c)) for c in columns] 528 568 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 529 569 while 1: … … 636 676 if table_prefix.endswith('.'): 637 677 table_prefix = backend.quote_name(table_prefix[:-1])+'.' 638 678 field_name = backend.quote_name(field_name) 679 #put some oracle exceptions here 680 if lookup_type == "icontains" and settings.DATABASE_ENGINE == 'oracle': 681 return 'lower(%s%s) %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) 639 682 try: 640 683 return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) 641 684 except KeyError: … … 667 710 Helper function that recursively populates the select, tables and where (in 668 711 place) for select_related queries. 669 712 """ 713 from django.db.models.fields import AutoField 670 714 qn = backend.quote_name 671 715 for f in opts.fields: 672 716 if f.rel and not f.null: … … 680 724 cache_tables_seen.append(db_table) 681 725 where.append('%s.%s = %s.%s' % \ 682 726 (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column))) 683 select.extend(['%s.%s' % (qn(db_table), qn(f2.column)) for f2 in f.rel.to._meta.fields]) 727 if settings.DATABASE_ENGINE == 'oracle': 728 select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields if not isinstance(f2, AutoField)]) 729 else: 730 select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields]) 684 731 fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) 685 732 686 733 def parse_lookup(kwarg_items, opts): -
db/backends/oracle/base.py
39 39 else: 40 40 conn_string = "%s/%s@%s" % (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME) 41 41 self.connection = Database.connect(conn_string) 42 # set oracle date to ansi date format 43 cursor = self.connection.cursor() 44 cursor.execute("alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'") 45 cursor.close() 42 46 return FormatStylePlaceholderCursor(self.connection) 43 47 44 48 def _commit(self): … … 67 71 def execute(self, query, params=None): 68 72 if params is None: params = [] 69 73 query = self.convert_arguments(query, len(params)) 70 return Database.Cursor.execute(self, query, params) 74 # cx can not execute the query with the closing ';' 75 if query.endswith(';') : 76 query = query[0:len(query)-1] 77 return Database.Cursor.execute(self, query, params) 71 78 72 79 def executemany(self, query, params=None): 73 80 if params is None: params = [] 74 81 query = self.convert_arguments(query, len(params[0])) 82 # cx can not execute the query with the closing ';' 83 if query.endswith(';') : 84 query = query[0:len(query)-1] 75 85 return Database.Cursor.executemany(self, query, params) 76 86 77 87 def convert_arguments(self, query, num_params): -
core/management.py
6 6 import os, re, shutil, sys, textwrap 7 7 from optparse import OptionParser 8 8 from django.utils import termcolors 9 from django.conf import settings 9 10 10 11 # For Python 2.3 11 12 if not hasattr(__builtins__, 'set'): … … 83 84 84 85 def get_sql_create(app): 85 86 "Returns a list of the CREATE TABLE SQL statements for the given app." 86 from django.db import get_creation_module, models87 from django.db import get_creation_module, backend 87 88 data_types = get_creation_module().DATA_TYPES 88 89 89 90 if not data_types: … … 181 182 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 182 183 full_statement.append(');') 183 184 final_output.append('\n'.join(full_statement)) 184 185 # To simulate auto-incrementing primary keys in Oracle -- creating primary tables 186 if (settings.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field): 187 sequence_statement = 'CREATE SEQUENCE %s_sq;' % opts.db_table 188 final_output.append(sequence_statement) 189 trigger_statement = '' + \ 190 'CREATE OR REPLACE trigger %s_tr\n' % opts.db_table + \ 191 ' before insert on %s\n' % backend.quote_name(opts.db_table) + \ 192 ' for each row\n' + \ 193 ' when (new.id is NULL)\n' + \ 194 ' begin\n' + \ 195 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % opts.db_table + \ 196 ' end;\n' 197 final_output.append(trigger_statement) 198 185 199 return final_output, pending_references 186 200 187 201 def _get_sql_for_pending_references(model, pending_references): … … 208 222 r_name += '_%s' % reference_names[r_name] 209 223 else: 210 224 reference_names[r_name] = 0 225 # if constraint name size is over 29 char and db is oracle, chop it 226 constraint_name = r_name 227 if settings.DATABASE_ENGINE == 'oracle' and len(constraint_name) > 29: 228 constraint_name = constraint_name[0:29] 211 229 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 212 (backend.quote_name(r_table), r_name,230 (backend.quote_name(r_table), constraint_name, 213 231 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 214 232 del pending_references[model] 215 233 return final_output … … 248 266 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 249 267 table_output.append(');') 250 268 final_output.append('\n'.join(table_output)) 269 # To simulate auto-incrementing primary keys in Oracle -- creating m2m tables 270 if (settings.DATABASE_ENGINE == 'oracle'): 271 m_table = f.m2m_db_table() 272 sequence_statement = 'CREATE SEQUENCE %s_sq;' % m_table 273 final_output.append(sequence_statement) 274 trigger_statement = '' + \ 275 'CREATE OR REPLACE trigger %s_tr\n' % m_table + \ 276 ' before insert on %s\n' % backend.quote_name(m_table) + \ 277 ' for each row\n' + \ 278 ' when (new.id is NULL)\n' + \ 279 ' begin\n' + \ 280 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % m_table + \ 281 ' end;\n' 282 final_output.append(trigger_statement) 251 283 return final_output 252 284 253 285 def get_sql_delete(app): … … 471 503 sql.extend(_get_sql_for_pending_references(model, pending_references)) 472 504 print "Creating table %s" % model._meta.db_table 473 505 for statement in sql: 474 cursor.execute(statement) 506 # go on if one table could not be created 507 try: 508 cursor.execute(statement) 509 except Exception, e: 510 print statement 511 print e 475 512 table_list.append(model._meta.db_table) 476 513 477 514 for model in model_list: … … 1281 1318 if not mod_list: 1282 1319 parser.print_usage_and_exit() 1283 1320 if action not in NO_SQL_TRANSACTION: 1284 print style.SQL_KEYWORD("BEGIN;") 1321 if settings.DATABASE_ENGINE != 'oracle': 1322 print style.SQL_KEYWORD("BEGIN;") 1285 1323 for mod in mod_list: 1286 1324 output = action_mapping[action](mod) 1287 1325 if output: 1288 1326 print '\n'.join(output) 1289 1327 if action not in NO_SQL_TRANSACTION: 1290 print style.SQL_KEYWORD("COMMIT;") 1328 if settings.DATABASE_ENGINE != 'oracle': 1329 print style.SQL_KEYWORD("COMMIT;") 1291 1330 1292 1331 def execute_manager(settings_mod, argv=None): 1293 1332 # Add this project to sys.path so that it's importable in the conventional -
contrib/admin/models.py
16 16 action_time = models.DateTimeField(_('action time'), auto_now=True) 17 17 user = models.ForeignKey(User) 18 18 content_type = models.ForeignKey(ContentType, blank=True, null=True) 19 object_id = models.TextField(_('object id'), blank=True, null=True) 19 #changed for Oracle support 20 object_id = models.CharField(_('object id'), maxlength=200, blank=True, null=True) 20 21 object_repr = models.CharField(_('object repr'), maxlength=200) 21 22 action_flag = models.PositiveSmallIntegerField(_('action flag')) 22 23 change_message = models.TextField(_('change message'), blank=True)