Ticket #87: oracle_patch_as_of_rev_2074.patch

File oracle_patch_as_of_rev_2074.patch, 21.0 KB (added by Jason Huggins, 15 years ago)

Updated patch for subversion rev #2074

  • django/contrib/admin/models/admin.py

     
    66    action_time = meta.DateTimeField(_('action time'), auto_now=True)
    77    user = meta.ForeignKey(auth.User)
    88    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
    1014    object_repr = meta.CharField(_('object repr'), maxlength=200)
    1115    action_flag = meta.PositiveSmallIntegerField(_('action flag'))
    1216    change_message = meta.TextField(_('change message'), blank=True)
  • django/core/db/__init__.py

     
    4040OPERATOR_MAPPING = dbmod.OPERATOR_MAPPING
    4141DATA_TYPES = dbmod.DATA_TYPES
    4242DATA_TYPES_REVERSE = dbmod.DATA_TYPES_REVERSE
     43EMPTY_STR_EQUIV = getattr(dbmod,'EMPTY_STR_EQUIV','')
  • django/core/meta/__init__.py

     
    995995    record_exists = True
    996996    if pk_set:
    997997        # 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" % \
    999999            (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)), [pk_val])
    10001000        # If it does already exist, do an UPDATE.
    10011001        if cursor.fetchone():
     
    11201120    cache_var = '_%s_cache' % field_with_rel.name
    11211121    if not hasattr(self, cache_var):
    11221122        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]),
    11251125            db.db.quote_name(rel.db_table),
    11261126            db.db.quote_name(field_with_rel.get_m2m_db_table(self._meta)),
    11271127            db.db.quote_name(rel.pk.column),
     
    13741374    kwargs['select'] = kwargs.get('select', {}).items()
    13751375
    13761376    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)
    13791379    fill_cache = kwargs.get('select_related')
    13801380    index_end = len(opts.fields)
    13811381    while 1:
     
    13991399    kwargs['offset'] = None
    14001400    kwargs['limit'] = None
    14011401    kwargs['select_related'] = False
    1402     _, sql, params = function_get_sql_clause(opts, **kwargs)
     1402    _, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
    14031403    cursor = db.db.cursor()
    14041404    cursor.execute("SELECT COUNT(*)" + sql, params)
    14051405    return cursor.fetchone()[0]
     
    14161416        fields = [f.column for f in opts.fields]
    14171417
    14181418    cursor = db.db.cursor()
    1419     _, sql, params = function_get_sql_clause(opts, **kwargs)
     1419    _, sql, params, full_query = function_get_sql_clause(opts, **kwargs)
    14201420    select = ['%s.%s' % (db.db.quote_name(opts.db_table), db.db.quote_name(f)) for f in fields]
    14211421    cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params)
    14221422    while 1:
     
    14471447            where.append('%s.%s = %s.%s' % \
    14481448                (db.db.quote_name(old_prefix), db.db.quote_name(f.column),
    14491449                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])
    14511451            _fill_table_cache(f.rel.to, select, tables, where, db_table, cache_tables_seen)
    14521452
    14531453def _throw_bad_kwarg_error(kwarg):
     
    16391639            order_by.append('%s%s %s' % (table_prefix, db.db.quote_name(orderfield2column(col_name, opts)), order))
    16401640    order_by = ", ".join(order_by)
    16411641
    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
    16451655    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                               
    16481696
    1649     return select, " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "") + limit_sql, params
    1650 
    16511697def function_get_in_bulk(opts, klass, *args, **kwargs):
    16521698    id_list = args and args[0] or kwargs.get('id_list', [])
    16531699    assert id_list != [], "get_in_bulk() cannot be passed an empty list."
     
    16741720    if field.null:
    16751721        kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \
    16761722            (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)
    16781724    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)
    16791725    cursor = db.db.cursor()
    16801726    cursor.execute(sql, params)
  • django/core/meta/fields.py

     
    11from django.conf import settings
     2from django.core import db
    23from django.core import formfields, validators
    34from django.core.exceptions import ObjectDoesNotExist
    45from django.utils.functional import curry, lazy
     
    171172
    172173    def get_db_prep_save(self, value):
    173174        "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
    174180        return value
    175181
    176182    def get_db_prep_lookup(self, lookup_type, value):
     
    180186        elif lookup_type in ('range', 'in'):
    181187            return value
    182188        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]
    184195        elif lookup_type in ('contains', 'icontains'):
    185196            return ["%%%s%%" % prep_for_like_query(value)]
    186197        elif lookup_type == 'iexact':
     
    368379        kwargs['blank'] = True
    369380        Field.__init__(self, *args, **kwargs)
    370381
     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
    371390    def get_manipulator_field_objs(self):
    372391        return [formfields.CheckboxField]
    373392
     
    388407            kwargs['editable'] = False
    389408            kwargs['blank'] = True
    390409        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           
    397434        return Field.get_db_prep_lookup(self, lookup_type, value)
    398435
    399436    def pre_save(self, value, add):
     
    411448    def get_db_prep_save(self, value):
    412449        # Casts dates into string format for entry into database.
    413450        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)
    416455
    417456    def get_manipulator_field_objs(self):
    418457        return [formfields.DateField]
     
    423462
    424463class DateTimeField(DateField):
    425464    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)
    434479
    435480    def get_manipulator_field_objs(self):
    436481        return [formfields.DateField, formfields.TimeField]
     
    629674        if auto_now or auto_now_add:
    630675            kwargs['editable'] = False
    631676        Field.__init__(self, verbose_name, name, **kwargs)
    632 
     677
    633678    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               
    638692        return Field.get_db_prep_lookup(self, lookup_type, value)
    639693
    640694    def pre_save(self, value, add):
     
    645699    def get_db_prep_save(self, value):
    646700        # Casts dates into string format for entry into database.
    647701        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)
    653712        return Field.get_db_prep_save(self, value)
    654713
    655714    def get_manipulator_field_objs(self):
  • django/core/management.py

     
    9797            full_statement.append('    %s%s' % (line, i < len(table_output)-1 and ',' or ''))
    9898        full_statement.append(');')
    9999        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                               
    100116
    101117    for klass in mod._MODELS:
    102118        opts = klass._meta
     
    118134                db.db.quote_name(f.rel.to.object_name.lower() + '_id')))
    119135            table_output.append(');')
    120136            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           
    121151    return final_output
    122152get_sql_create.help_doc = "Prints the CREATE TABLE SQL statements for the given model module name(s)."
    123153get_sql_create.args = APP_ARGS
     
    135165    try:
    136166        if cursor is not None:
    137167            # 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'))
    139169    except:
    140170        # The table doesn't exist, so it doesn't need to be dropped.
    141171        db.db.rollback()
     
    150180        try:
    151181            if cursor is not None:
    152182                # 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))
    154184        except:
    155185            # The table doesn't exist, so it doesn't need to be dropped.
    156186            db.db.rollback()
    157187        else:
    158188            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)
    159192
    160193    # Output DROP TABLE statements for many-to-many tables.
    161194    for klass in mod._MODELS:
     
    163196        for f in opts.many_to_many:
    164197            try:
    165198                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)))
    167200            except:
    168201                db.db.rollback()
    169202            else:
    170203                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))               
    171207
    172208    app_label = mod._MODELS[0]._meta.app_label
    173209
     
    963999                addr, port = '', args[1]
    9641000        action_mapping[action](addr, port)
    9651001    else:
    966         from django.core import meta
     1002        from django.core import meta, db
    9671003        if action == 'dbcheck':
    9681004            mod_list = meta.get_all_installed_modules()
    9691005        else:
     
    9751011            if not mod_list:
    9761012                parser.print_usage_and_exit()
    9771013        if action not in NO_SQL_TRANSACTION:
    978             print "BEGIN;"
     1014            if db.DATABASE_ENGINE != 'oracle':
     1015                print "BEGIN;"
    9791016        for mod in mod_list:
    9801017            output = action_mapping[action](mod)
    9811018            if output:
    9821019                print '\n'.join(output)
    9831020        if action not in NO_SQL_TRANSACTION:
    984             print "COMMIT;"
     1021            if db.DATABASE_ENGINE != 'oracle':
     1022                print "COMMIT;"
    9851023
    9861024def execute_manager(settings_mod):
    9871025    # Add this project to sys.path so that it's importable in the conventional
Back to Top