1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

queryset-refactor: An attempt to fix an ambiguous column error that can arise

in Oracle queries. Adds an options to add output column aliases.

The testing I can do shows that the query is being constructed correctly. I
haven't run the test against an Oracle install, though.

Refs #7057 (ticket can be closed if the Oracle tests pass).


git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@7457 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-04-25 06:54:35 +00:00
parent 8a4e1de8b0
commit 6657d476d0
2 changed files with 44 additions and 13 deletions

View File

@ -72,7 +72,7 @@ def query_class(QueryClass, Database):
values.append(value)
return values
def as_sql(self, with_limits=True):
def as_sql(self, with_limits=True, with_col_aliases=False):
"""
Creates the SQL for this query. Returns the SQL string and list
of parameters. This is overriden from the original Query class
@ -88,7 +88,8 @@ def query_class(QueryClass, Database):
# If no offsets, just return the result of the base class
# `as_sql`.
if not do_offset:
return super(OracleQuery, self).as_sql(with_limits=False)
return super(OracleQuery, self).as_sql(with_limits=False,
with_col_aliases=with_col_aliases)
# `get_columns` needs to be called before `get_ordering` to
# populate `_select_alias`.
@ -110,7 +111,8 @@ def query_class(QueryClass, Database):
# Getting the selection SQL and the params, which has the `rn`
# extra selection SQL.
self.extra_select['rn'] = 'ROW_NUMBER() OVER (ORDER BY %s )' % rn_orderby
sql, params= super(OracleQuery, self).as_sql(with_limits=False)
sql, params= super(OracleQuery, self).as_sql(with_limits=False,
with_col_aliases=True)
# Constructing the result SQL, using the initial select SQL
# obtained above.

View File

@ -206,7 +206,7 @@ class Query(object):
return number
def as_sql(self, with_limits=True):
def as_sql(self, with_limits=True, with_col_aliases=False):
"""
Creates the SQL for this query. Returns the SQL string and list of
parameters.
@ -215,7 +215,7 @@ class Query(object):
in the query.
"""
self.pre_sql_setup()
out_cols = self.get_columns()
out_cols = self.get_columns(with_col_aliases)
ordering = self.get_ordering()
# This must come after 'select' and 'ordering' -- see docstring of
@ -354,38 +354,62 @@ class Query(object):
if self.select_related and not self.related_select_cols:
self.fill_related_selections()
def get_columns(self):
def get_columns(self, with_aliases=False):
"""
Return the list of columns to use in the select statement. If no
columns have been specified, returns all columns relating to fields in
the model.
If 'with_aliases' is true, any column names that are duplicated
(without the table names) are given unique aliases. This is needed in
some cases to avoid ambiguitity with nested queries.
"""
qn = self.quote_name_unless_alias
result = ['(%s) AS %s' % (col, alias) for alias, col in self.extra_select.iteritems()]
aliases = self.extra_select.keys()
if with_aliases:
col_aliases = set(aliases)
else:
col_aliases = set()
if self.select:
for col in self.select:
if isinstance(col, (list, tuple)):
r = '%s.%s' % (qn(col[0]), qn(col[1]))
if with_aliases and col[1] in col_aliases:
c_alias = 'Col%d' % len(col_aliases)
result.append('%s AS %s' % (r, c_alias))
aliases.append(c_alias)
col_aliases.add(c_alias)
else:
result.append(r)
aliases.append(r)
col_aliases.add(col[1])
else:
result.append(col.as_sql(quote_func=qn))
if hasattr(col, 'alias'):
aliases.append(col.alias)
col_aliases.add(col.alias)
elif self.default_cols:
cols = self.get_default_columns(True)
cols = self.get_default_columns(True, with_aliases, col_aliases)
result.extend(cols)
aliases.extend(cols)
for table, col in self.related_select_cols:
r = '%s.%s' % (qn(table), qn(col))
if with_aliases and col in col_aliases:
c_alias = 'Col%d' % len(col_aliases)
result.append('%s AS %s' % (r, c_alias))
aliases.append(c_alias)
col_aliases.add(c_alias)
else:
result.append(r)
aliases.append(r)
col_aliases.add(col)
self._select_aliases = set(aliases)
return result
def get_default_columns(self, as_str=False):
def get_default_columns(self, as_str=False, with_aliases=False,
col_aliases=None):
"""
Computes the default columns for selecting every field in the base
model. Returns a list of default (alias, column) pairs suitable for
@ -406,6 +430,11 @@ class Query(object):
root_pk, model._meta.pk.column))
seen[model] = alias
if as_str:
if with_aliases and field.column in col_aliases:
c_alias = 'Col%d' % len(col_aliases)
result.append('%s.%s AS %s' % (qn(alias),
qn2(field.column), c_aliase))
else:
result.append('%s.%s' % (qn(alias), qn2(field.column)))
else:
result.append((alias, field.column))