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:
parent
8a4e1de8b0
commit
6657d476d0
@ -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.
|
||||
|
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user