Ticket #87: oracle_patch_as_of_rev_2074.patch
File oracle_patch_as_of_rev_2074.patch, 21.0 KB (added by , 19 years ago) |
---|
-
django/contrib/admin/models/admin.py
6 6 action_time = meta.DateTimeField(_('action time'), auto_now=True) 7 7 user = meta.ForeignKey(auth.User) 8 8 content_type = meta.ForeignKey(core.ContentType, blank=True, null=True) 9 object_id = meta.TextField(_('object id'), blank=True, null=True) 9 # begin JRH see http://code.djangoproject.com/ticket/304 10 # "Changes to auth.LogEntry in changeset [469] breaks Oracle backend." 11 #object_id = meta.TextField(_('object id'), blank=True, null=True) 12 object_id = meta.CharField(_('object id'), maxlength=100, blank=True, null=True) 13 # end JRH 10 14 object_repr = meta.CharField(_('object repr'), maxlength=200) 11 15 action_flag = meta.PositiveSmallIntegerField(_('action flag')) 12 16 change_message = meta.TextField(_('change message'), blank=True) -
django/core/db/__init__.py
40 40 OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING 41 41 DATA_TYPES = dbmod.DATA_TYPES 42 42 DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE 43 EMPTY_STR_EQUIV = getattr(dbmod,'EMPTY_STR_EQUIV','') -
django/core/meta/__init__.py
995 995 record_exists = True 996 996 if pk_set: 997 997 # Determine whether a record with the primary key already exists. 998 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \998 cursor.execute("SELECT 1 FROM %s WHERE %s=%%s" % \ 999 999 (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)), [pk_val]) 1000 1000 # If it does already exist, do an UPDATE. 1001 1001 if cursor.fetchone(): … … 1120 1120 cache_var = '_%s_cache' % field_with_rel.name 1121 1121 if not hasattr(self, cache_var): 1122 1122 mod = rel.get_model_module() 1123 sql = "SELECT %s FROM %s a, %s b WHERE a.%s = b.%s AND b.%s = %%s %s"% \1124 (','.join([' a.%s' % db.db.quote_name(f.column) for f in rel.fields]),1123 sql = 'SELECT %s FROM %s "a", %s "b" WHERE "a".%s = "b".%s AND "b".%s = %%s %s' % \ 1124 (','.join(['"a".%s' % db.db.quote_name(f.column) for f in rel.fields]), 1125 1125 db.db.quote_name(rel.db_table), 1126 1126 db.db.quote_name(field_with_rel.get_m2m_db_table(self._meta)), 1127 1127 db.db.quote_name(rel.pk.column), … … 1374 1374 kwargs['select'] = kwargs.get('select', {}).items() 1375 1375 1376 1376 cursor = db.db.cursor() 1377 select, sql, params = function_get_sql_clause(opts, **kwargs)1378 cursor.execute( "SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)1377 select, sql, params, full_query = function_get_sql_clause(opts, **kwargs) 1378 cursor.execute(full_query, params) 1379 1379 fill_cache = kwargs.get('select_related') 1380 1380 index_end = len(opts.fields) 1381 1381 while 1: … … 1399 1399 kwargs['offset'] = None 1400 1400 kwargs['limit'] = None 1401 1401 kwargs['select_related'] = False 1402 _, sql, params = function_get_sql_clause(opts, **kwargs)1402 _, sql, params, full_query = function_get_sql_clause(opts, **kwargs) 1403 1403 cursor = db.db.cursor() 1404 1404 cursor.execute("SELECT COUNT(*)" + sql, params) 1405 1405 return cursor.fetchone()[0] … … 1416 1416 fields = [f.column for f in opts.fields] 1417 1417 1418 1418 cursor = db.db.cursor() 1419 _, sql, params = function_get_sql_clause(opts, **kwargs)1419 _, sql, params, full_query = function_get_sql_clause(opts, **kwargs) 1420 1420 select = ['%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(f)) for f in fields] 1421 1421 cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params) 1422 1422 while 1: … … 1447 1447 where.append('%s.%s = %s.%s' % \ 1448 1448 (db.db.quote_name(old_prefix), db.db.quote_name(f.column), 1449 1449 db.db.quote_name(db_table), db.db.quote_name(f.rel.get_related_field().column))) 1450 select.extend(['%s.%s ' % (db.db.quote_name(db_table), db.db.quote_name(f2.column)) for f2 in f.rel.to.fields])1450 select.extend(['%s.%s as "%s.%s"' % (db.db.quote_name(db_table), db.db.quote_name(f2.column), db_table, f2.column) for f2 in f.rel.to.fields]) 1451 1451 _fill_table_cache(f.rel.to, select, tables, where, db_table, cache_tables_seen) 1452 1452 1453 1453 def _throw_bad_kwarg_error(kwarg): … … 1639 1639 order_by.append('%s%s %s' % (table_prefix, db.db.quote_name(orderfield2column(col_name, opts)), order)) 1640 1640 order_by = ", ".join(order_by) 1641 1641 1642 # LIMIT and OFFSET clauses 1643 if kwargs.get('limit') is not None: 1644 limit_sql = " %s " % db.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset')) 1642 sql = " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "") 1643 1644 if (db.DATABASE_ENGINE != 'oracle'): 1645 # LIMIT and OFFSET clauses 1646 if kwargs.get('limit') is not None: 1647 limit_sql = " %s " % db.get_limit_offset_sql(kwargs['limit'], kwargs.get('offset')) 1648 else: 1649 assert kwargs.get('offset') is None, "'offset' is not allowed without 'limit'" 1650 limit_sql = "" 1651 1652 1653 full_query = "SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql + limit_sql 1654 return select, sql + limit_sql, params, full_query 1645 1655 else: 1646 assert kwargs.get('offset') is None, "'offset' is not allowed without 'limit'" 1647 limit_sql = "" 1656 # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 1657 1658 select_clause = ",".join(select) 1659 distinct = (kwargs.get('distinct') and "DISTINCT " or "") 1660 from_clause = ",".join(tables) 1661 where_clause = (where and " WHERE " + " AND ".join(where) or "") 1662 1663 if order_by: 1664 order_by_clause = " OVER (ORDER BY %s )" % (order_by) 1665 else: 1666 #Oracle's row_number() function always requires an order-by clause. 1667 #So we need to define a default order-by, since none was provided. 1668 order_by_clause = " OVER (ORDER BY %s.%s)" % \ 1669 (db.db.quote_name(opts.db_table), 1670 db.db.quote_name(opts.fields[0].name)) 1671 1672 # limit_and_offset_clause 1673 limit = kwargs.get('limit',0) 1674 offset = kwargs.get('offset',0) 1675 if offset == None: 1676 offset = 0 1677 1678 limit_and_offset_clause = '' 1679 if limit: 1680 limit = int(limit) 1681 offset = int(offset) 1682 limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 1683 else: 1684 limit_and_offset_clause = "WHERE rn > %s" % (offset) 1685 1686 full_query = """SELECT * FROM 1687 (SELECT %s 1688 %s, 1689 ROW_NUMBER() %s AS rn 1690 FROM %s 1691 %s 1692 ) 1693 %s 1694 """ % (distinct, select_clause, order_by_clause, from_clause, where_clause, limit_and_offset_clause) 1695 return select, sql, params, full_query 1648 1696 1649 return select, " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "") + limit_sql, params1650 1651 1697 def function_get_in_bulk(opts, klass, *args, **kwargs): 1652 1698 id_list = args and args[0] or kwargs.get('id_list', []) 1653 1699 assert id_list != [], "get_in_bulk() cannot be passed an empty list." … … 1674 1720 if field.null: 1675 1721 kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \ 1676 1722 (db.db.quote_name(opts.db_table), db.db.quote_name(field.column))) 1677 select, sql, params = function_get_sql_clause(opts, **kwargs)1723 select, sql, params, full_query = function_get_sql_clause(opts, **kwargs) 1678 1724 sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1' % (db.get_date_trunc_sql(kind, '%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(field.column))), sql) 1679 1725 cursor = db.db.cursor() 1680 1726 cursor.execute(sql, params) -
django/core/meta/fields.py
1 1 from django.conf import settings 2 from django.core import db 2 3 from django.core import formfields, validators 3 4 from django.core.exceptions import ObjectDoesNotExist 4 5 from django.utils.functional import curry, lazy … … 171 172 172 173 def get_db_prep_save(self, value): 173 174 "Returns field's value prepared for saving into a database." 175 176 # Oracle treats empty strings ('') the same as NULLs. 177 # To get around this wart, we need to change it to something else... 178 if value == '': 179 value = db.EMPTY_STR_EQUIV 174 180 return value 175 181 176 182 def get_db_prep_lookup(self, lookup_type, value): … … 180 186 elif lookup_type in ('range', 'in'): 181 187 return value 182 188 elif lookup_type == 'year': 183 return ['%s-01-01' % value, '%s-12-31' % value] 189 if settings.DATABASE_ENGINE == 'oracle': 190 from_dt = datetime.date(int(value), 01, 01) 191 to_dt = datetime.date(int(value), 12, 31) 192 return [from_dt, to_dt] 193 else: 194 return ['%s-01-01' % value, '%s-12-31' % value] 184 195 elif lookup_type in ('contains', 'icontains'): 185 196 return ["%%%s%%" % prep_for_like_query(value)] 186 197 elif lookup_type == 'iexact': … … 368 379 kwargs['blank'] = True 369 380 Field.__init__(self, *args, **kwargs) 370 381 382 def get_db_prep_lookup(self, lookup_type, value): 383 if settings.DATABASE_ENGINE == 'oracle': 384 if value == 'True': 385 value = 1 386 elif value == 'False': 387 value = 0 388 return Field.get_db_prep_lookup(self, lookup_type, value) 389 371 390 def get_manipulator_field_objs(self): 372 391 return [formfields.CheckboxField] 373 392 … … 388 407 kwargs['editable'] = False 389 408 kwargs['blank'] = True 390 409 Field.__init__(self, verbose_name, name, **kwargs) 391 392 def get_db_prep_lookup(self, lookup_type, value): 393 if lookup_type == 'range': 394 value = [str(v) for v in value] 395 else: 396 value = str(value) 410 411 def get_db_prep_lookup(self, lookup_type, value): 412 # Oracle driver can deal with datetime.time objects natively 413 # and doesn't need to convert to string 414 if settings.DATABASE_ENGINE == 'oracle': 415 if lookup_type == 'range': 416 value = [v for v in value] 417 #elif lookup_type == 'day': 418 # value = int(value) 419 elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte', 'ne'): 420 if type(value) == str: 421 pattern = r'^\d\d\d\d-\d\d-\d\d$' # "YYYY-MM-DD" 422 from re import search 423 if search(pattern, value) != None: 424 year, month, day = map(int, value.split('-')) 425 value = datetime.date(year, month, day) 426 else: 427 value = value 428 else: 429 if lookup_type == 'range': 430 value = [str(v) for v in value] 431 else: 432 value = str(value) 433 397 434 return Field.get_db_prep_lookup(self, lookup_type, value) 398 435 399 436 def pre_save(self, value, add): … … 411 448 def get_db_prep_save(self, value): 412 449 # Casts dates into string format for entry into database. 413 450 if value is not None: 414 value = value.strftime('%Y-%m-%d') 415 return Field.get_db_prep_save(self, value) 451 if settings.DATABASE_ENGINE != 'oracle': 452 #Oracle does not need a string conversion 453 value = value.strftime('%Y-%m-%d') 454 return Field.get_db_prep_save(self, value) 416 455 417 456 def get_manipulator_field_objs(self): 418 457 return [formfields.DateField] … … 423 462 424 463 class DateTimeField(DateField): 425 464 def get_db_prep_save(self, value): 426 # Casts dates into string format for entry into database. 427 if value is not None: 428 # MySQL will throw a warning if microseconds are given, because it 429 # doesn't support microseconds. 430 if settings.DATABASE_ENGINE == 'mysql': 431 value = value.replace(microsecond=0) 432 value = str(value) 433 return Field.get_db_prep_save(self, value) 465 # Casts dates into string format for entry into database. 466 if value is not None: 467 # MySQL will throw a warning if microseconds are given, because it 468 # doesn't support microseconds. 469 if settings.DATABASE_ENGINE == 'mysql': 470 value = value.replace(microsecond=0) 471 value = str(value) 472 # Oracle will choke if microseconds are given... 473 elif settings.DATABASE_ENGINE == 'oracle': 474 value = value.replace(microsecond=0) 475 else: 476 value = str(value) 477 478 return Field.get_db_prep_save(self, value) 434 479 435 480 def get_manipulator_field_objs(self): 436 481 return [formfields.DateField, formfields.TimeField] … … 629 674 if auto_now or auto_now_add: 630 675 kwargs['editable'] = False 631 676 Field.__init__(self, verbose_name, name, **kwargs) 632 677 633 678 def get_db_prep_lookup(self, lookup_type, value): 634 if lookup_type == 'range': 635 value = [str(v) for v in value] 636 else: 637 value = str(value) 679 # Oracle driver can deal with datetime.time objects natively 680 # and doesn't need to convert to string 681 if settings.DATABASE_ENGINE == 'oracle': 682 if lookup_type == 'range': 683 value = [v for v in value] 684 else: 685 value = value 686 else: 687 if lookup_type == 'range': 688 value = [str(v) for v in value] 689 else: 690 value = str(value) 691 638 692 return Field.get_db_prep_lookup(self, lookup_type, value) 639 693 640 694 def pre_save(self, value, add): … … 645 699 def get_db_prep_save(self, value): 646 700 # Casts dates into string format for entry into database. 647 701 if value is not None: 648 # MySQL will throw a warning if microseconds are given, because it 649 # doesn't support microseconds. 650 if settings.DATABASE_ENGINE == 'mysql': 651 value = value.replace(microsecond=0) 652 value = str(value) 702 # MySQL will throw a warning if microseconds are given, because it 703 # doesn't support microseconds. 704 if settings.DATABASE_ENGINE == 'mysql': 705 value = value.replace(microsecond=0) 706 value = str(value) 707 # Oracle will choke if microseconds are given... 708 elif settings.DATABASE_ENGINE == 'oracle': 709 value = value.replace(microsecond=0) 710 else: 711 value = str(value) 653 712 return Field.get_db_prep_save(self, value) 654 713 655 714 def get_manipulator_field_objs(self): -
django/core/management.py
97 97 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 98 98 full_statement.append(');') 99 99 final_output.append('\n'.join(full_statement)) 100 101 if (db.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field): 102 # To simulate auto-incrementing primary keys in Oracle 103 104 sequence_statement = 'CREATE SEQUENCE "%s_sq";' % opts.db_table 105 final_output.append(sequence_statement) 106 107 trigger_statement = '' + \ 108 'CREATE OR REPLACE trigger "%s_tr"\n' % opts.db_table + \ 109 ' before insert on %s\n' % db.db.quote_name(opts.db_table) + \ 110 ' for each row\n' + \ 111 ' begin\n' + \ 112 ' select "%s_sq".NEXTVAL into :new."id" from DUAL;\n' % opts.db_table + \ 113 ' end;\n' 114 final_output.append(trigger_statement) 115 100 116 101 117 for klass in mod._MODELS: 102 118 opts = klass._meta … … 118 134 db.db.quote_name(f.rel.to.object_name.lower() + '_id'))) 119 135 table_output.append(');') 120 136 final_output.append('\n'.join(table_output)) 137 138 if (db.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field): 139 sequence_statement = 'CREATE SEQUENCE "%s_sq";' % f.get_m2m_db_table(opts) 140 final_output.append(sequence_statement) 141 142 trigger_statement = "" + \ 143 'CREATE OR REPLACE trigger "%s_tr"\n' % f.get_m2m_db_table(opts) + \ 144 ' before insert on "%s"\n' % f.get_m2m_db_table(opts) + \ 145 ' for each row\n' + \ 146 ' begin\n' + \ 147 ' select "%s_sq".NEXTVAL into :new."id" from DUAL;\n' % f.get_m2m_db_table(opts) + \ 148 ' end;\n' 149 final_output.append(trigger_statement) 150 121 151 return final_output 122 152 get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given model module name(s)." 123 153 get_sql_create.args = APP_ARGS … … 135 165 try: 136 166 if cursor is not None: 137 167 # Check whether the table exists. 138 cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name('django_admin_log'))168 cursor.execute("SELECT 1 FROM %s" % db.db.quote_name('django_admin_log')) 139 169 except: 140 170 # The table doesn't exist, so it doesn't need to be dropped. 141 171 db.db.rollback() … … 150 180 try: 151 181 if cursor is not None: 152 182 # Check whether the table exists. 153 cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(klass._meta.db_table))183 cursor.execute("SELECT 1 FROM %s" % db.db.quote_name(klass._meta.db_table)) 154 184 except: 155 185 # The table doesn't exist, so it doesn't need to be dropped. 156 186 db.db.rollback() 157 187 else: 158 188 output.append("DROP TABLE %s;" % db.db.quote_name(klass._meta.db_table)) 189 if db.DATABASE_ENGINE == 'oracle': 190 output.append('DROP SEQUENCE "%s_sq";' % klass._meta.db_table) 191 output.append('DROP TRIGGER "%s_tr";' % klass._meta.db_table) 159 192 160 193 # Output DROP TABLE statements for many-to-many tables. 161 194 for klass in mod._MODELS: … … 163 196 for f in opts.many_to_many: 164 197 try: 165 198 if cursor is not None: 166 cursor.execute("SELECT 1 FROM %s LIMIT 1" % db.db.quote_name(f.get_m2m_db_table(opts)))199 cursor.execute("SELECT 1 FROM %s" % db.db.quote_name(f.get_m2m_db_table(opts))) 167 200 except: 168 201 db.db.rollback() 169 202 else: 170 203 output.append("DROP TABLE %s;" % db.db.quote_name(f.get_m2m_db_table(opts))) 204 if db.DATABASE_ENGINE == 'oracle': 205 output.append('DROP SEQUENCE "%s_sq";' % f.get_m2m_db_table(opts)) 206 output.append('DROP TRIGGER "%s_tr";' % f.get_m2m_db_table(opts)) 171 207 172 208 app_label = mod._MODELS[0]._meta.app_label 173 209 … … 963 999 addr, port = '', args[1] 964 1000 action_mapping[action](addr, port) 965 1001 else: 966 from django.core import meta 1002 from django.core import meta, db 967 1003 if action == 'dbcheck': 968 1004 mod_list = meta.get_all_installed_modules() 969 1005 else: … … 975 1011 if not mod_list: 976 1012 parser.print_usage_and_exit() 977 1013 if action not in NO_SQL_TRANSACTION: 978 print "BEGIN;" 1014 if db.DATABASE_ENGINE != 'oracle': 1015 print "BEGIN;" 979 1016 for mod in mod_list: 980 1017 output = action_mapping[action](mod) 981 1018 if output: 982 1019 print '\n'.join(output) 983 1020 if action not in NO_SQL_TRANSACTION: 984 print "COMMIT;" 1021 if db.DATABASE_ENGINE != 'oracle': 1022 print "COMMIT;" 985 1023 986 1024 def execute_manager(settings_mod): 987 1025 # Add this project to sys.path so that it's importable in the conventional