Django

Code

Changeset 4078

Show
Ignore:
Timestamp:
11/16/06 10:25:59 (2 years ago)
Author:
bouldersprinters
Message:

boulder-oracle-sprint: Fixed Oracle limit-offset logic and many_to_one test
case.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/branches/boulder-oracle-sprint/django/db/backends/oracle/base.py

    r4066 r4078  
    7070    This fixes it -- but note that if you want to use a literal "%s" in a query, 
    7171    you'll need to use "%%s". 
    72     """     
     72    """ 
    7373    def _rewrite_args(self, query, params=None): 
    74         if params is None:  
     74        if params is None: 
    7575            params = [] 
    7676        args = [(':arg%d' % i) for i in range(len(params))] 
    7777        query = query % tuple(args) 
    78         # cx_Oracle cannot execute a query with the closing ';'  
     78        # cx_Oracle cannot execute a query with the closing ';' 
    7979        if query.endswith(';'): 
    8080            query = query[:-1] 
    8181        return query, params 
    82      
     82 
    8383    def execute(self, query, params=None): 
    8484        query, params = self._rewrite_args(query, params) 
     
    9191        return Database.Cursor.executemany(self, query, params) 
    9292 
    93      
     93 
    9494def quote_name(name): 
    95     # Oracle requires that quoted names be uppercase.     
     95    # Oracle requires that quoted names be uppercase. 
    9696    name = name.upper() 
    9797    if not name.startswith('"') and not name.endswith('"'): 
     
    144144OPERATOR_MAPPING = { 
    145145    'exact': '= %s', 
    146     'iexact': 'LIKE %s'
    147     'contains': 'LIKE %s'
    148     'icontains': 'LIKE %s'
     146    'iexact': "LIKE %s ESCAPE '\\'"
     147    'contains': "LIKE %s ESCAPE '\\'"
     148    'icontains': "LIKE %s ESCAPE '\\'"
    149149    'gt': '> %s', 
    150150    'gte': '>= %s', 
    151151    'lt': '< %s', 
    152152    'lte': '<= %s', 
    153     'startswith': 'LIKE %s'
    154     'endswith': 'LIKE %s'
    155     'istartswith': 'LIKE %s'
    156     'iendswith': 'LIKE %s'
     153    'startswith': "LIKE %s ESCAPE '\\'"
     154    'endswith': "LIKE %s ESCAPE '\\'"
     155    'istartswith': "LIKE %s ESCAPE '\\'"
     156    'iendswith': "LIKE %s ESCAPE '\\'"
    157157} 
  • django/branches/boulder-oracle-sprint/django/db/backends/oracle/creation.py

    r4064 r4078  
    4646    try: 
    4747        _create_test_db(cursor, TEST_DATABASE_NAME, verbosity) 
    48     except Exception, e:             
     48    except Exception, e: 
    4949        sys.stderr.write("Got an error creating the test database: %s\n" % e) 
    5050        if not autoclobber: 
     
    6464            print "Tests cancelled." 
    6565            sys.exit(1) 
    66                 
     66 
    6767    connection.close() 
    6868    settings.DATABASE_USER = TEST_DATABASE_NAME 
     
    7272    # the side effect of initializing the test database. 
    7373    cursor = connection.cursor() 
    74          
     74 
    7575def destroy_test_db(settings, connection, backend, old_database_name, verbosity=1): 
    7676    if verbosity >= 1: 
     
    106106    ] 
    107107    _execute_statements(cursor, statements, dbname, verbosity) 
    108      
     108 
    109109def _destroy_test_db(cursor, dbname, verbosity): 
    110110    if verbosity >= 2: 
  • django/branches/boulder-oracle-sprint/django/db/backends/oracle/query.py

    r4064 r4078  
    2323    place) for select_related queries. 
    2424    """ 
    25     from django.db.models.fields import AutoField  
     25    from django.db.models.fields import AutoField 
    2626    qn = backend.quote_name 
    2727    for f in opts.fields: 
     
    3737            where.append('%s.%s = %s.%s' % \ 
    3838                (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column))) 
    39             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)])  
     39            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)]) 
    4040            fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) 
    4141 
     
    4343def get_query_set_class(DefaultQuerySet): 
    4444    "Create a custom QuerySet class for Oracle." 
    45      
     45 
    4646    class OracleQuerySet(DefaultQuerySet): 
    47          
     47 
    4848        def iterator(self): 
    4949            "Performs the SELECT database lookup of this QuerySet." 
     
    5454 
    5555            full_query = None 
     56 
    5657            select, sql, params, full_query = self._get_sql_clause() 
    5758            if not full_query: 
     
    5960                             ((self._distinct and "DISTINCT " or ""), 
    6061                              ', '.join(select), sql) 
    61                  
     62 
    6263            cursor = connection.cursor() 
    63             cursor.execute(full_query, params)  
     64            cursor.execute(full_query, params) 
    6465 
    6566            fill_cache = self._select_related 
     
    8990        def _get_sql_clause(self): 
    9091            opts = self.model._meta 
    91      
     92 
    9293            # Construct the fundamental parts of the query: SELECT X FROM Y WHERE Z. 
    9394            select = ["%s.%s" % (backend.quote_name(opts.db_table), backend.quote_name(f.column)) for f in opts.fields] 
     
    9697            where = self._where[:] 
    9798            params = self._params[:] 
    98          
     99 
    99100            # Convert self._filters into SQL. 
    100101            joins2, where2, params2 = self._filters.get_sql(opts) 
     
    102103            where.extend(where2) 
    103104            params.extend(params2) 
    104      
     105 
    105106            # Add additional tables and WHERE clauses based on select_related. 
    106107            if self._select_related: 
    107108                fill_table_cache(opts, select, tables, where, opts.db_table, [opts.db_table]) 
    108      
     109 
    109110            # Add any additional SELECTs. 
    110111            if self._select: 
    111112                select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), backend.quote_name(s[0])) for s in self._select.items()]) 
    112      
     113 
    113114            # Start composing the body of the SQL statement. 
    114115            sql = [" FROM", backend.quote_name(opts.db_table)] 
    115      
     116 
    116117            # Compose the join dictionary into SQL describing the joins. 
    117118            if joins: 
    118119                sql.append(" ".join(["%s %s %s ON %s" % (join_type, table, alias, condition) 
    119120                                for (alias, (table, join_type, condition)) in joins.items()])) 
    120      
     121 
    121122            # Compose the tables clause into SQL. 
    122123            if tables: 
    123124                sql.append(", " + ", ".join(tables)) 
    124      
     125 
    125126            # Compose the where clause into SQL. 
    126127            if where: 
    127128                sql.append(where and "WHERE " + " AND ".join(where)) 
    128      
     129 
    129130            # ORDER BY clause 
    130131            order_by = [] 
     
    156157            if order_by: 
    157158                sql.append("ORDER BY " + ", ".join(order_by)) 
    158      
     159 
    159160            # LIMIT and OFFSET clauses 
    160             # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query.  
    161             select_clause = ",".join(select)  
    162             distinct = (self._distinct and "DISTINCT " or "")  
    163  
    164             if order_by:   
    165                 order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by))  
    166             else: 
    167                 #Oracle's row_number() function always requires an order-by clause.  
    168                 #So we need to define a default order-by, since none was provided.  
     161            # To support limits and offsets, Oracle requires some funky rewriting of an otherwise normal looking query. 
     162            select_clause = ",".join(select) 
     163            distinct = (self._distinct and "DISTINCT " or "") 
     164 
     165            if order_by: 
     166                order_by_clause = " OVER (ORDER BY %s )" % (", ".join(order_by)) 
     167            else: 
     168                #Oracle's row_number() function always requires an order-by clause. 
     169                #So we need to define a default order-by, since none was provided. 
    169170                order_by_clause = " OVER (ORDER BY %s.%s)" % \ 
    170                     (backend.quote_name(opts.db_table),   
    171                     backend.quote_name(opts.fields[0].db_column or opts.fields[0].column))  
    172             # limit_and_offset_clause  
    173             offset = self._offset and int(self._offset) or 0  
    174             limit = self._limit and int(self._limit) or None  
    175             limit_and_offset_clause = ''  
    176             if limit:  
    177                 limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset)  
     171                    (backend.quote_name(opts.db_table), 
     172                    backend.quote_name(opts.fields[0].db_column or opts.fields[0].column)) 
     173            # limit_and_offset_clause 
     174            if self._limit is None: 
     175                assert self._offset is None, "'offset' is not allowed without 'limit'" 
     176 
     177            if self._offset is not None: 
     178                offset = int(self._offset) 
     179            else: 
     180                offset = 0 
     181            if self._limit is not None: 
     182                limit = int(self._limit) 
     183            else: 
     184                limit = None 
     185 
     186            limit_and_offset_clause = '' 
     187            if limit is not None: 
     188                limit_and_offset_clause = "WHERE rn > %s AND rn <= %s" % (offset, limit+offset) 
    178189            elif offset: 
    179                 limit_and_offset_clause = "WHERE rn > %s" % (offset)  
    180  
    181             if len(limit_and_offset_clause) > 0:  
    182                 full_query = """SELECT * FROM   
    183                     (SELECT %s     
    184                     %s,  
    185                     ROW_NUMBER() %s AS rn  
    186                     %s  
    187                     )  
    188                     %s  
     190                limit_and_offset_clause = "WHERE rn > %s" % (offset) 
     191 
     192            if len(limit_and_offset_clause) > 0: 
     193                full_query = """SELECT * FROM 
     194                    (SELECT %s 
     195                    %s, 
     196                    ROW_NUMBER() %s AS rn 
     197                    %s 
     198                    ) 
     199                    %s 
    189200                    """ % (distinct, select_clause, order_by_clause, " ".join(sql), limit_and_offset_clause) 
    190201            else: 
    191                 full_query = None  
    192               
     202                full_query = None 
     203 
    193204            return select, " ".join(sql), params, full_query 
    194              
     205 
    195206    return OracleQuerySet 
  • django/branches/boulder-oracle-sprint/django/db/models/query.py

    r4066 r4078  
    170170 
    171171        cursor = connection.cursor() 
    172          
    173         select, sql, params, full_query = self._get_sql_clause()  
    174         cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params)  
     172 
     173        select, sql, params, full_query = self._get_sql_clause() 
     174        cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 
    175175 
    176176        fill_cache = self._select_related 
     
    519519else: 
    520520    QuerySet = _QuerySet 
    521              
     521 
    522522class ValuesQuerySet(QuerySet): 
    523523    def iterator(self): 
     
    568568            cursor = connection.cursor() 
    569569            cursor.execute(sql, params) 
    570             return [row[0] for row in cursor.fetchall()]   
     570            return [row[0] for row in cursor.fetchall()] 
    571571        else: 
    572572            sql = fmt % (date_trunc_sql, sql, 1, self._order_by) 
     
    661661    if settings.DATABASE_ENGINE == 'oracle': 
    662662        if lookup_type == 'icontains': 
    663             return 'lower(%s%s) %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s'))              
     663            return 'lower(%s%s) %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) 
    664664        elif type(value) == datetime.datetime: 
    665665            return "%s%s %s" % (table_prefix, field_name, 
    666                  (backend.OPERATOR_MAPPING[lookup_type] % "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS')"))        
     666                 (backend.OPERATOR_MAPPING[lookup_type] % "TO_TIMESTAMP(%s, 'YYYY-MM-DD HH24:MI:SS')")) 
    667667    try: 
    668668        return '%s%s %s' % (table_prefix, field_name, (backend.OPERATOR_MAPPING[lookup_type] % '%s')) 
     
    696696    place) for select_related queries. 
    697697    """ 
    698     from django.db.models.fields import AutoField  
     698    from django.db.models.fields import AutoField 
    699699    qn = backend.quote_name 
    700700    for f in opts.fields: 
     
    710710            where.append('%s.%s = %s.%s' % \ 
    711711                (qn(old_prefix), qn(f.column), qn(db_table), qn(f.rel.get_related_field().column))) 
    712             select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields])  
     712            select.extend(['%s.%s' % (backend.quote_name(db_table), backend.quote_name(f2.column)) for f2 in f.rel.to._meta.fields]) 
    713713            fill_table_cache(f.rel.to._meta, select, tables, where, db_table, cache_tables_seen) 
    714714 
     
    755755        if len(path) < 1: 
    756756            raise TypeError, "Cannot parse keyword query %r" % kwarg 
    757          
     757 
    758758        if value is None: 
    759759            # Interpret '__exact=None' as the sql '= NULL'; otherwise, reject 
  • django/branches/boulder-oracle-sprint/tests/modeltests/many_to_one/models.py

    r3661 r4078  
    147147# The underlying query only makes one join when a related table is referenced twice. 
    148148>>> query = Article.objects.filter(reporter__first_name__exact='John', reporter__last_name__exact='Smith') 
    149 >>> null, sql, null = query._get_sql_clause() 
     149>>> null, sql, null, null = query._get_sql_clause() 
    150150>>> sql.count('INNER JOIN') 
    1511511 
     
    156156 
    157157# Find all Articles for the Reporter whose ID is 1. 
    158 # Use direct ID check, pk check, and object comparison  
     158# Use direct ID check, pk check, and object comparison 
    159159>>> Article.objects.filter(reporter__id__exact=1) 
    160160[<Article: John's second story>, <Article: This is a test>]