Skip to content

Instantly share code, notes, and snippets.

@jarshwah
Last active August 29, 2015 14:12
Show Gist options
  • Save jarshwah/35adcc1916216aecfd38 to your computer and use it in GitHub Desktop.
Save jarshwah/35adcc1916216aecfd38 to your computer and use it in GitHub Desktop.
oracle fix notes
diff --git a/django/db/backends/oracle/compiler.py b/django/db/backends/oracle/compiler.py
index cfc8a08..12d9ad6 100644
--- a/django/db/backends/oracle/compiler.py
+++ b/django/db/backends/oracle/compiler.py
@@ -20,12 +20,12 @@ class SQLCompiler(compiler.SQLCompiler):
do_offset = with_limits and (self.query.high_mark is not None
or self.query.low_mark)
if not do_offset:
- sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
- with_col_aliases=with_col_aliases)
+ sql, params = super(SQLCompiler, self).as_sql(
+ with_limits=False, with_col_aliases=with_col_aliases)
else:
- sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
- with_col_aliases=True)
-
+ print ('with_aliases!')
+ sql, params = super(SQLCompiler, self).as_sql(
+ with_limits=False, with_col_aliases=True)
# Wrap the base query in an outer SELECT * with boundaries on
# the "_RN" column. This is the canonical way to emulate LIMIT
# and OFFSET on Oracle.
@@ -36,7 +36,7 @@ class SQLCompiler(compiler.SQLCompiler):
'SELECT * FROM (SELECT "_SUB".*, ROWNUM AS "_RN" FROM (%s) '
'"_SUB" %s) WHERE "_RN" > %d' % (sql, high_where, self.query.low_mark)
)
-
+ print (sql)
return sql, params
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index a0d60f1..b1128ed 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -526,14 +526,16 @@ class ColIndexRef(ExpressionNode):
class Col(ExpressionNode):
- def __init__(self, alias, target, source=None):
+ def __init__(self, alias, target, source=None, column_alias=None):
if source is None:
source = target
super(Col, self).__init__(output_field=source)
- self.alias, self.target = alias, target
+ self.alias, self.target, self.column_alias = alias, target, column_alias
def as_sql(self, compiler, connection):
qn = compiler.quote_name_unless_alias
+ #if self.column_alias is not None:
+ # return "%s.%s AS %s" % (qn(self.alias), qn(self.target.column), self.column_alias), []
return "%s.%s" % (qn(self.alias), qn(self.target.column)), []
def relabeled_clone(self, relabels):
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index cdfd1b7..bcc6c08 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -292,12 +292,12 @@ class Field(RegisterLookupMixin):
def _check_backend_specific_checks(self, **kwargs):
return connection.validation.check_field(self, **kwargs)
- def get_col(self, alias, source=None):
+ def get_col(self, alias, source=None, column_alias=None):
if source is None:
source = self
- if alias != self.model._meta.db_table or source != self:
+ if alias != self.model._meta.db_table or source != self or column_alias is not None:
from django.db.models.expressions import Col
- return Col(alias, self, source)
+ return Col(alias, self, source, column_alias)
else:
return self.cached_col
diff --git a/django/db/models/query.py b/django/db/models/query.py
index de2279a..e373f94 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -237,8 +237,8 @@ class QuerySet(object):
# Execute the query. This will also fill compiler.select, klass_info and
# annotations.
results = compiler.execute_sql()
- select, klass_info, annotation_col_map = (compiler.select, compiler.klass_info,
- compiler.annotation_col_map)
+ select, klass_info, annotation_col_map = (
+ compiler.select, compiler.klass_info, compiler.annotation_col_map)
if klass_info is None:
return
model_cls = klass_info['model']
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index e590f3b..2218bef 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -29,19 +29,19 @@ class SQLCompiler(object):
self.annotation_col_map = None
self.klass_info = None
- def setup_query(self):
+ def setup_query(self, with_col_aliases=False):
if all(self.query.alias_refcount[a] == 0 for a in self.query.tables):
self.query.get_initial_alias()
- self.select, self.klass_info, self.annotation_col_map = self.get_select()
+ self.select, self.klass_info, self.annotation_col_map = self.get_select(with_col_aliases=with_col_aliases)
self.col_count = len(self.select)
- def pre_sql_setup(self):
+ def pre_sql_setup(self, with_col_aliases=False):
"""
Does any necessary class setup immediately prior to producing SQL. This
is for things that can't necessarily be done in __init__ because we
might not have all the pieces in place at that time.
"""
- self.setup_query()
+ self.setup_query(with_col_aliases=with_col_aliases)
order_by = self.get_order_by()
extra_select = self.get_extra_select(order_by, self.select)
group_by = self.get_group_by(self.select + extra_select, order_by)
@@ -145,7 +145,7 @@ class SQLCompiler(object):
expressions = [pk] + [expr for expr in expressions if expr in having]
return expressions
- def get_select(self):
+ def get_select(self, with_col_aliases=False):
"""
Returns a list of 3-tuples of (expression, (sql, params), alias), a klass_info
structure and annotations found.
@@ -172,9 +172,9 @@ class SQLCompiler(object):
assert not (self.query.select and self.query.default_cols)
if self.query.default_cols:
select_list = []
- for c in self.get_default_columns():
+ for c in self.get_default_columns(with_col_aliases=with_col_aliases):
select_list.append(select_idx)
- select.append((c, None))
+ select.append((c, c.column_alias))
select_idx += 1
klass_info = {
'model': self.query.model,
@@ -183,7 +183,7 @@ class SQLCompiler(object):
# self.query.select is a special case. These columns never go to
# any model.
for col in self.query.select:
- select.append((col, None))
+ select.append((col, col.column_alias))
select_idx += 1
for alias, annotation in self.query.annotation_select.items():
annotations[alias] = select_idx
@@ -191,7 +191,7 @@ class SQLCompiler(object):
select_idx += 1
if self.query.select_related:
- related_klass_infos = self.get_related_selections(select)
+ related_klass_infos = self.get_related_selections(select, with_col_aliases=with_col_aliases)
klass_info['related_klass_infos'] = related_klass_infos
def get_select_from_parent(klass_info):
@@ -327,6 +327,10 @@ class SQLCompiler(object):
If 'with_limits' is False, any limit/offset information is not included
in the query.
"""
+ # don't bother setting up the query if the limit is a no-op.
+ if with_limits and self.query.low_mark == self.query.high_mark:
+ return '', ()
+
# After executing the query, we must get rid of any joins the query
# setup created. So, take note of alias counts before the query ran.
# However we do not want to get rid of stuff done in pre_sql_setup(),
@@ -334,9 +338,7 @@ class SQLCompiler(object):
# another run of it.
refcounts_before = self.query.alias_refcount.copy()
try:
- extra_select, order_by, group_by = self.pre_sql_setup()
- if with_limits and self.query.low_mark == self.query.high_mark:
- return '', ()
+ extra_select, order_by, group_by = self.pre_sql_setup(with_col_aliases=with_col_aliases)
distinct_fields = self.get_distinct()
# This must come after 'select', 'ordering' and 'distinct' -- see
@@ -352,7 +354,10 @@ class SQLCompiler(object):
result.append(self.connection.ops.distinct_sql(distinct_fields))
out_cols = []
- for _, (s_sql, s_params), alias in self.select + extra_select:
+ for X, (s_sql, s_params), alias in self.select + extra_select:
+ print('X:: ', X)
+ print('s_sql:: ', s_sql)
+ print('alias:: ', alias)
if alias:
s_sql = '%s AS %s' % (s_sql, self.connection.ops.quote_name(alias))
params.extend(s_params)
@@ -432,7 +437,7 @@ class SQLCompiler(object):
obj.clear_ordering(True)
return obj.get_compiler(connection=self.connection).as_sql()
- def get_default_columns(self, start_alias=None, opts=None, from_parent=None):
+ def get_default_columns(self, start_alias=None, opts=None, from_parent=None, with_col_aliases=False):
"""
Computes the default columns for selecting every field in the base
model. Will sometimes be called to pull in related models (e.g. via
@@ -454,7 +459,7 @@ class SQLCompiler(object):
# alias for a given field. This also includes None -> start_alias to
# be used by local fields.
seen_models = {None: start_alias}
-
+ counter = 0
for field, model in opts.get_concrete_fields_with_model():
if from_parent and model is not None and issubclass(
from_parent._meta.concrete_model, model._meta.concrete_model):
@@ -466,8 +471,8 @@ class SQLCompiler(object):
continue
if field.model in only_load and field.attname not in only_load[field.model]:
continue
- alias = self.query.join_parent_model(opts, model, start_alias,
- seen_models)
+ alias = self.query.join_parent_model(
+ opts, model, start_alias, seen_models)
column = field.get_col(alias)
result.append(column)
return result
@@ -573,7 +578,7 @@ class SQLCompiler(object):
return result, params
def get_related_selections(self, select, opts=None, root_alias=None, cur_depth=1,
- requested=None, restricted=None):
+ requested=None, restricted=None, with_col_aliases=False):
"""
Fill in the information needed for a select_related query. The current
depth is measured as the number of connections away from the root model
@@ -648,10 +653,10 @@ class SQLCompiler(object):
opts=f.rel.to._meta)
for col in columns:
select_fields.append(len(select))
- select.append((col, None))
+ select.append((col, col.column_alias))
klass_info['select_fields'] = select_fields
next_klass_infos = self.get_related_selections(
- select, f.rel.to._meta, alias, cur_depth + 1, next, restricted)
+ select, f.rel.to._meta, alias, cur_depth + 1, next, restricted, with_col_aliases=with_col_aliases)
get_related_klass_infos(klass_info, next_klass_infos)
if restricted:
@@ -679,12 +684,12 @@ class SQLCompiler(object):
start_alias=alias, opts=model._meta, from_parent=opts.model)
for col in columns:
select_fields.append(len(select))
- select.append((col, None))
+ select.append((col, col.column_alias))
klass_info['select_fields'] = select_fields
next = requested.get(f.related_query_name(), {})
next_klass_infos = self.get_related_selections(
select, model._meta, alias, cur_depth + 1,
- next, restricted)
+ next, restricted, with_col_aliases=with_col_aliases)
get_related_klass_infos(klass_info, next_klass_infos)
fields_not_found = set(requested.keys()).difference(fields_found)
if fields_not_found:
@@ -1012,7 +1017,7 @@ class SQLUpdateCompiler(SQLCompiler):
is_empty = False
return rows
- def pre_sql_setup(self):
+ def pre_sql_setup(self, with_col_aliases=False):
"""
If the update depends on results from other tables, we need to do some
munging of the "where" conditions to match the format required for
diff --git a/tests/queries/tests.py b/tests/queries/tests.py
index 855b09b..3cbd19b 100644
--- a/tests/queries/tests.py
+++ b/tests/queries/tests.py
@@ -415,8 +415,10 @@ class Queries1Tests(BaseQuerysetTest):
)
def test_ticket2496(self):
+ qs = Item.objects.extra(tables=['queries_author']).select_related().order_by('name')
+ print(qs.query)
self.assertQuerysetEqual(
- Item.objects.extra(tables=['queries_author']).select_related().order_by('name')[:1],
+ qs[:1],
['<Item: four>']
)
@@ -1137,7 +1139,6 @@ class Queries1Tests(BaseQuerysetTest):
# A negated Q along with an annotated queryset failed in Django 1.4
qs = Author.objects.annotate(Count('item'))
qs = qs.filter(~Q(extra__value=0))
-
self.assertIn('SELECT', str(qs.query))
self.assertQuerysetEqual(
qs,
diff --git a/django/db/backends/oracle/compiler.py b/django/db/backends/oracle/compiler.py
index cfc8a08..d68159a 100644
--- a/django/db/backends/oracle/compiler.py
+++ b/django/db/backends/oracle/compiler.py
@@ -20,11 +20,11 @@ class SQLCompiler(compiler.SQLCompiler):
do_offset = with_limits and (self.query.high_mark is not None
or self.query.low_mark)
if not do_offset:
- sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
- with_col_aliases=with_col_aliases)
+ sql, params = super(SQLCompiler, self).as_sql(
+ with_limits=False, with_col_aliases=with_col_aliases)
else:
- sql, params = super(SQLCompiler, self).as_sql(with_limits=False,
- with_col_aliases=True)
+ sql, params = super(SQLCompiler, self).as_sql(
+ with_limits=False, with_col_aliases=True)
# Wrap the base query in an outer SELECT * with boundaries on
# the "_RN" column. This is the canonical way to emulate LIMIT
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index e590f3b..c35a11c 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -327,6 +327,9 @@ class SQLCompiler(object):
If 'with_limits' is False, any limit/offset information is not included
in the query.
"""
+ # don't bother setting up the query if the limit is a no-op.
+ if with_limits and self.query.low_mark == self.query.high_mark:
+ return '', ()
# After executing the query, we must get rid of any joins the query
# setup created. So, take note of alias counts before the query ran.
# However we do not want to get rid of stuff done in pre_sql_setup(),
@@ -335,8 +338,6 @@ class SQLCompiler(object):
refcounts_before = self.query.alias_refcount.copy()
try:
extra_select, order_by, group_by = self.pre_sql_setup()
- if with_limits and self.query.low_mark == self.query.high_mark:
- return '', ()
distinct_fields = self.get_distinct()
# This must come after 'select', 'ordering' and 'distinct' -- see
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment