Ticket #18330: django-ticket18330.diff

File django-ticket18330.diff, 5.6 KB (added by Michael Manfre, 12 years ago)

Adds raw_limit_offset_select with better documentation and more flexibility for limit and offset.

  • django/core/cache/backends/db.py

    diff --git a/django/core/cache/backends/db.py b/django/core/cache/backends/db.py
    index 62ea5c4..0b2a77e 100644
    a b class DatabaseCache(BaseDatabaseCache):  
    167167            num = cursor.fetchone()[0]
    168168            if num > self._max_entries:
    169169                cull_num = num / self._cull_frequency
    170                 if connections[db].vendor == 'oracle':
    171                     # Oracle doesn't support LIMIT + OFFSET
    172                     cursor.execute("""SELECT cache_key FROM
    173 (SELECT ROW_NUMBER() OVER (ORDER BY cache_key) AS counter, cache_key FROM %s)
    174 WHERE counter > %%s AND COUNTER <= %%s""" % table, [cull_num, cull_num + 1])
    175                 else:
    176                     # This isn't standard SQL, it's likely to break
    177                     # with some non officially supported databases
    178                     cursor.execute("SELECT cache_key FROM %s "
    179                                    "ORDER BY cache_key "
    180                                    "LIMIT 1 OFFSET %%s" % table, [cull_num])
     170
     171                sql, params = connections[db].ops.raw_limit_offset_select(
     172                    fields='cache_key',
     173                    table=table,
     174                    order_by='cache_key',
     175                    limit=1,
     176                    offset=cull_num,
     177                )
     178                cursor.execute(sql, params)
     179
    181180                cursor.execute("DELETE FROM %s "
    182181                               "WHERE cache_key < %%s" % table,
    183182                               [cursor.fetchone()[0]])
  • django/db/backends/__init__.py

    diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py
    index 2762350..15926e2 100644
    a b class BaseDatabaseOperations(object):  
    874874        conn = ' %s ' % connector
    875875        return conn.join(sub_expressions)
    876876
     877    def raw_limit_offset_select(self, fields, table, limit, offset=None, where=None, order_by=None):
     878        """
     879        Returns a two element tuple with the raw SQL string to do a simple
     880        select with limit + offset and a list of parameters to provide to the
     881        cursor with the SQL.
     882
     883        It is the caller's responsibilty to properly quote any entities in
     884        `fields`, `table`, and `order_by`.
     885        """
     886        params = []
     887        sql = "SELECT %s FROM %s" % (fields, table)
     888        if where:
     889            sql += " WHERE %s" % where
     890        if order_by:
     891              sql += " ORDER BY %s " % order_by
     892        if limit:
     893            sql += " LIMIT %s"
     894            params.append(limit)
     895            if offset:
     896                sql += " OFFSET %s"
     897                params.append(offset)
     898        return sql, params
     899
    877900class BaseDatabaseIntrospection(object):
    878901    """
    879902    This class encapsulates all backend-specific introspection utilities
  • django/db/backends/oracle/base.py

    diff --git a/django/db/backends/oracle/base.py b/django/db/backends/oracle/base.py
    index 2f3a43d..dd0b0ff 100644
    a b WHEN (new.%(col_name)s IS NULL)  
    389389        items_sql = "SELECT %s FROM DUAL" % ", ".join(["%s"] * len(fields))
    390390        return " UNION ALL ".join([items_sql] * num_values)
    391391
     392    def raw_limit_offset_select(self, fields, table, limit, offset=None, where=None, order_by=None):
     393        sql = "SELECT %s FROM " \
     394              "(SELECT ROW_NUMBER() OVER (ORDER BY cache_key) AS counter, %s" \
     395              " FROM %s)" % (fields, fields, table)
     396        where_parts, params = [], []
     397        if where:
     398            where_parts.append('(%s)' % where)
     399        if offset is not None:
     400            where_parts.append('counter > %s')
     401            params.append(offset)
     402        if limit is not None:
     403            where_parts.append('counter <= %s')
     404            params.append((offset + limit) if offset else limit)
     405        if where_parts:
     406            sql += ' WHERE %s' % ' AND '.join(where_parts)
     407        return sql, params
    392408
    393409class _UninitializedOperatorsDescriptor(object):
    394410
  • tests/regressiontests/aggregation_regress/tests.py

    diff --git a/tests/regressiontests/aggregation_regress/tests.py b/tests/regressiontests/aggregation_regress/tests.py
    index 36a54c0..676be2f 100644
    a b from decimal import Decimal  
    66from operator import attrgetter
    77
    88from django.core.exceptions import FieldError
     9from django.db import connection
    910from django.db.models import Count, Max, Avg, Sum, StdDev, Variance, F, Q
    1011from django.test import TestCase, Approximate, skipUnlessDBFeature
    1112
    class AggregationTests(TestCase):  
    6667        Regression test for #11916: Extra params + aggregation creates
    6768        incorrect SQL.
    6869        """
    69         #oracle doesn't support subqueries in group by clause
    70         shortest_book_sql = """
    71         SELECT name
    72         FROM aggregation_regress_book b
    73         WHERE b.publisher_id = aggregation_regress_publisher.id
    74         ORDER BY b.pages
    75         LIMIT 1
    76         """
     70        qn = connection.ops.quote_name
     71        sql, params = connection.ops.raw_limit_offset_select(
     72            fields=qn('name'),
     73            table=qn('aggregation_regress_book'),
     74            where='%s = %s.%s' % (qn('publisher_id'), qn('aggregation_regress_publisher'), qn('id')),
     75            order_by=qn('pages'),
     76            limit=1,
     77        )
     78        shortest_book_sql = sql % params[0]
    7779        # tests that this query does not raise a DatabaseError due to the full
    7880        # subselect being (erroneously) added to the GROUP BY parameters
    7981        qs = Publisher.objects.extra(select={
Back to Top