Django

Code

Ticket #87: oracle_patch_as_of_rev_2074.patch

File oracle_patch_as_of_rev_2074.patch, 21.0 kB (added by Jason Huggins, 2 years ago)

Updated patch for subversion rev #2074

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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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

    old new  
    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