Ticket #1990: 0.95_plus_timestamp.patch
File 0.95_plus_timestamp.patch, 19.6 KB (added by , 18 years ago) |
---|
-
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) -
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' -
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: … … 157 158 field_output.append(style.SQL_KEYWORD('UNIQUE')) 158 159 if f.primary_key: 159 160 field_output.append(style.SQL_KEYWORD('PRIMARY KEY')) 161 if (settings.DATABASE_ENGINE == 'oracle') and f.unique and f.primary_key: 162 # Suppress UNIQUE/PRIMARY KEY for Oracle (ORA-02259) 163 field_output.remove(style.SQL_KEYWORD('UNIQUE')) 160 164 if f.rel: 161 165 if f.rel.to in known_models: 162 166 field_output.append(style.SQL_KEYWORD('REFERENCES') + ' ' + \ … … 181 185 full_statement.append(' %s%s' % (line, i < len(table_output)-1 and ',' or '')) 182 186 full_statement.append(');') 183 187 final_output.append('\n'.join(full_statement)) 188 189 # To simulate auto-incrementing primary keys in Oracle -- creating primary tables 190 if (settings.DATABASE_ENGINE == 'oracle') & (opts.has_auto_field): 191 sequence_statement = 'CREATE SEQUENCE %s_sq;' % opts.db_table 192 final_output.append(sequence_statement) 193 trigger_statement = '' + \ 194 'CREATE OR REPLACE trigger %s_tr\n' % opts.db_table + \ 195 ' before insert on %s\n' % backend.quote_name(opts.db_table) + \ 196 ' for each row\n' + \ 197 ' when (new.id is NULL)\n' + \ 198 ' begin\n' + \ 199 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % opts.db_table + \ 200 ' end;\n' 201 final_output.append(trigger_statement) 184 202 203 185 204 return final_output, pending_references 186 205 187 206 def _get_sql_for_pending_references(model, pending_references): … … 208 227 r_name += '_%s' % reference_names[r_name] 209 228 else: 210 229 reference_names[r_name] = 0 211 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, 213 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 230 # if constraint name size is over 29 char and db is oracle, chop it 231 if settings.DATABASE_ENGINE == 'oracle' and len(r_name) > 29: 232 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 233 (backend.quote_name(r_table), r_name[0:29], 234 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 235 else: 236 final_output.append(style.SQL_KEYWORD('ALTER TABLE') + ' %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s);' % \ 237 (backend.quote_name(r_table), r_name, 238 backend.quote_name(r_col), backend.quote_name(table), backend.quote_name(col))) 214 239 del pending_references[model] 215 240 return final_output 216 241 … … 248 273 style.SQL_FIELD(backend.quote_name(f.m2m_reverse_name())))) 249 274 table_output.append(');') 250 275 final_output.append('\n'.join(table_output)) 276 # To simulate auto-incrementing primary keys in Oracle -- creating m2m tables 277 if (settings.DATABASE_ENGINE == 'oracle'): 278 m_table = f.m2m_db_table() 279 sequence_statement = 'CREATE SEQUENCE %s_sq;' % m_table 280 final_output.append(sequence_statement) 281 trigger_statement = '' + \ 282 'CREATE OR REPLACE trigger %s_tr\n' % m_table + \ 283 ' before insert on %s\n' % backend.quote_name(m_table) + \ 284 ' for each row\n' + \ 285 ' when (new.id is NULL)\n' + \ 286 ' begin\n' + \ 287 ' select %s_sq.NEXTVAL into :new.id from DUAL;\n' % m_table + \ 288 ' end;\n' 289 final_output.append(trigger_statement) 251 290 return final_output 252 291 253 292 def get_sql_delete(app): … … 471 510 sql.extend(_get_sql_for_pending_references(model, pending_references)) 472 511 print "Creating table %s" % model._meta.db_table 473 512 for statement in sql: 474 cursor.execute(statement) 513 # go on if one table could not be created 514 try: 515 cursor.execute(statement) 516 except Exception, e: 517 print statement 518 print e 475 519 table_list.append(model._meta.db_table) 476 520 477 521 for model in model_list: … … 1281 1325 if not mod_list: 1282 1326 parser.print_usage_and_exit() 1283 1327 if action not in NO_SQL_TRANSACTION: 1284 print style.SQL_KEYWORD("BEGIN;") 1328 if settings.DATABASE_ENGINE != 'oracle': 1329 print style.SQL_KEYWORD("BEGIN;") 1285 1330 for mod in mod_list: 1286 1331 output = action_mapping[action](mod) 1287 1332 if output: 1288 1333 print '\n'.join(output) 1289 1334 if action not in NO_SQL_TRANSACTION: 1290 print style.SQL_KEYWORD("COMMIT;") 1335 if settings.DATABASE_ENGINE != 'oracle': 1336 print style.SQL_KEYWORD("COMMIT;") 1291 1337 1292 1338 def execute_manager(settings_mod, argv=None): 1293 1339 # Add this project to sys.path so that it's importable in the conventional -
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): -
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): … … 476 482 def get_db_prep_save(self, value): 477 483 # Casts dates into string format for entry into database. 478 484 if value is not None: 479 # MySQL will throw a warning if microseconds are given, because it485 # MySQL/Oracle will throw a warning if microseconds are given, because it 480 486 # doesn't support microseconds. 481 if settings.DATABASE_ENGINE == 'mysql'and hasattr(value, 'microsecond'):487 if (settings.DATABASE_ENGINE == 'mysql' or settings.DATABASE_ENGINE=='oracle') and hasattr(value, 'microsecond'): 482 488 value = value.replace(microsecond=0) 483 489 value = str(value) 484 490 return Field.get_db_prep_save(self, value) 485 491 486 492 def get_db_prep_lookup(self, lookup_type, value): 493 # Oracle will throw an error if microseconds are given, because it 494 # doesn't support microseconds. 495 if (settings.DATABASE_ENGINE=='oracle') and hasattr(value, 'microsecond'): 496 value = value.replace(microsecond=0) 487 497 if lookup_type == 'range': 488 498 value = [str(v) for v in value] 489 499 else: … … 511 521 def flatten_data(self,follow, obj = None): 512 522 val = self._get_val_from_obj(obj) 513 523 date_field, time_field = self.get_manipulator_field_names('') 514 return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''), 515 time_field: (val is not None and val.strftime("%H:%M:%S") or '')} 524 #cx_Oracle does not support strftime 525 if (settings.DATABASE_ENGINE=='oracle'): 526 return {date_field: (val is not None or ''), 527 time_field: (val is not None or '')} 528 else: 529 return {date_field: (val is not None and val.strftime("%Y-%m-%d") or ''), 530 time_field: (val is not None and val.strftime("%H:%M:%S") or '')} 516 531 517 532 class EmailField(CharField): 518 533 def __init__(self, *args, **kwargs): … … 744 759 # doesn't support microseconds. 745 760 if settings.DATABASE_ENGINE == 'mysql': 746 761 value = value.replace(microsecond=0) 747 value = str(value) 762 value = str(value) 763 elif settings.DATABASE_ENGINE == 'oracle': 764 value = value.replace(microsecond=0) 765 # cx_Oracle expects a datetime.datetime to persist into TIMESTAMP field. 766 value = datetime.datetime(1900, 1, 1, value.hour, value.minute, value.second) 767 else: 768 value = str(value) 748 769 return Field.get_db_prep_save(self, value) 749 770 750 771 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):