Ticket #1990: django_oracle3545.patch
File django_oracle3545.patch, 18.4 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): … … 449 453 def get_db_prep_save(self, value): 450 454 # Casts dates into string format for entry into database. 451 455 if value is not None: 452 value = value.strftime('%Y-%m-%d') 456 if settings.DATABASE_ENGINE != 'oracle': 457 #Oracle does not need a string conversion 458 value = value.strftime('%Y-%m-%d') 453 459 return Field.get_db_prep_save(self, value) 454 460 455 461 def get_manipulator_field_objs(self): … … 479 485 def get_db_prep_save(self, value): 480 486 # Casts dates into string format for entry into database. 481 487 if value is not None: 482 # MySQL will throw a warning if microseconds are given, because it488 # MySQL/Oracle will throw a warning if microseconds are given, because it 483 489 # doesn't support microseconds. 484 if settings.DATABASE_ENGINE == 'mysql'and hasattr(value, 'microsecond'):490 if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE=='oracle') and hasattr(value, 'microsecond'): 485 491 value = value.replace(microsecond=0) 486 492 value = str(value) 487 493 return Field.get_db_prep_save(self, value) 488 494 489 495 def get_db_prep_lookup(self, lookup_type, value): 496 # Oracle will throw an error if microseconds are given, because it 497 # doesn't support microseconds. 498 if (settings.DATABASE_ENGINE=='oracle') and hasattr(value, 'microsecond'): 499 value = value.replace(microsecond=0) 490 500 if lookup_type == 'range': 491 501 value = [str(v) for v in value] 492 502 else: … … 514 524 def flatten_data(self,follow, obj = None): 515 525 val = self._get_val_from_obj(obj) 516 526 date_field, time_field = self.get_manipulator_field_names('') 517 return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''), 518 time_field: (val is not None and val.strftime("%H:%M:%S") or '')} 527 #cx_Oracle does not support strftime 528 if (settings.DATABASE_ENGINE=='oracle'): 529 return {date_field: (val is not None or ''), 530 time_field: (val is not None or '')} 531 else: 532 return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''), 533 time_field: (val is not None and val.strftime("%H:%M:%S") or '')} 519 534 520 535 class EmailField(CharField): 521 536 def __init__(self, *args, **kwargs): … … 747 762 # doesn't support microseconds. 748 763 if settings.DATABASE_ENGINE == 'mysql': 749 764 value = value.replace(microsecond=0) 750 value = str(value) 765 value = str(value) 766 elif settings.DATABASE_ENGINE == 'oracle': 767 value = value.replace(microsecond=0) 768 else: 769 value = str(value) 751 770 return Field.get_db_prep_save(self, value) 752 771 753 772 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 elif 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 print query 78 print params 79 return Database.Cursor.execute(self, query, params) 71 80 72 81 def executemany(self, query, params=None): 73 82 if params is None: params = [] 74 83 query = self.convert_arguments(query, len(params[0])) 84 # cx can not execute the query with the closing ';' 85 if query.endswith(';') : 86 query = query[0:len(query)-1] 75 87 return Database.Cursor.executemany(self, query, params) 76 88 77 89 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 models,get_creation_module, backend 87 88 data_types = get_creation_module().DATA_TYPES 88 89 89 90 if not data_types: … … 187 188 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 188 189 full_statement.append(');') 189 190 final_output.append('\n'.join(full_statement)) 190 191 # To simulate auto-incrementing primary keys in Oracle -- creating primary tables 192 if (settings.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field): 193 sequence_statement = 'CREATE SEQUENCE %s_sq;' % opts.db_table 194 final_output.append(sequence_statement) 195 trigger_statement = '' + \ 196 'CREATE OR REPLACE trigger %s_tr\n' % opts.db_table + \ 197 ' before insert on %s\n' % backend.quote_name(opts.db_table) + \ 198 ' for each row\n' + \ 199 ' when (new.id is NULL)\n' + \ 200 ' begin\n' + \ 201 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % opts.db_table + \ 202 ' end;\n' 203 final_output.append(trigger_statement) 204 191 205 return final_output, pending_references 192 206 193 207 def _get_sql_for_pending_references(model, pending_references): … … 210 224 # For MySQL, r_name must be unique in the first 64 characters. 211 225 # So we are careful with character usage here. 212 226 r_name = '%s_refs_%s_%x' % (r_col, col, abs(hash((r_table, table)))) 213 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 227 # if constraint name size is over 29 char and db is oracle, chop it 228 if settings.DATABASE_ENGINE == 'oracle' and len(r_name) > 29: 229 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 230 (backend.quote_name(r_table), r_name[0:29], 231 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 232 else: 233 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 214 234 (backend.quote_name(r_table), r_name, 215 235 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 216 236 del pending_references[model] … … 250 270 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 251 271 table_output.append(');') 252 272 final_output.append('\n'.join(table_output)) 273 # To simulate auto-incrementing primary keys in Oracle -- creating m2m tables 274 if (settings.DATABASE_ENGINE == 'oracle'): 275 m_table = f.m2m_db_table() 276 sequence_statement = 'CREATE SEQUENCE %s_sq;' % m_table 277 final_output.append(sequence_statement) 278 trigger_statement = '' + \ 279 'CREATE OR REPLACE trigger %s_tr\n' % m_table + \ 280 ' before insert on %s\n' % backend.quote_name(m_table) + \ 281 ' for each row\n' + \ 282 ' when (new.id is NULL)\n' + \ 283 ' begin\n' + \ 284 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % m_table + \ 285 ' end;\n' 286 final_output.append(trigger_statement) 253 287 return final_output 254 288 255 289 def get_sql_delete(app): … … 473 507 sql.extend(_get_sql_for_pending_references(model, pending_references)) 474 508 print "Creating table %s" % model._meta.db_table 475 509 for statement in sql: 476 cursor.execute(statement) 510 # go on if one table could not be created 511 try: 512 cursor.execute(statement) 513 except Exception, e: 514 print statement 515 print e 477 516 table_list.append(model._meta.db_table) 478 517 479 518 for model in model_list: … … 1289 1328 if not mod_list: 1290 1329 parser.print_usage_and_exit() 1291 1330 if action not in NO_SQL_TRANSACTION: 1292 print style.SQL_KEYWORD("BEGIN;") 1331 if settings.DATABASE_ENGINE != 'oracle': 1332 print style.SQL_KEYWORD("BEGIN;") 1293 1333 for mod in mod_list: 1294 1334 output = action_mapping[action](mod) 1295 1335 if output: 1296 1336 print '\n'.join(output) 1297 1337 if action not in NO_SQL_TRANSACTION: 1298 print style.SQL_KEYWORD("COMMIT;") 1338 if settings.DATABASE_ENGINE != 'oracle': 1339 print style.SQL_KEYWORD("COMMIT;") 1299 1340 1300 1341 def setup_environ(settings_mod): 1301 1342 """ -
contrib/sessions/models.py
51 51 session_key = models.CharField(_('session key'), maxlength=40, primary_key=True) 52 52 session_data = models.TextField(_('session data')) 53 53 expire_date = models.DateTimeField(_('expire date')) 54 54 55 objects = SessionManager() 55 56 class Meta: 56 57 db_table = 'django_session' -
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)