summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2012-07-10 11:00:49 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2012-07-10 11:00:49 -0400
commit0e41673ed4e8551b892c058ffc6a607cf7aba71c (patch)
tree6914091d7cbb58331d147242e6efa83bd1345424
parentb297b40fca923a03e3c34094e5298d6524944c39 (diff)
downloadsqlalchemy-0e41673ed4e8551b892c058ffc6a607cf7aba71c.tar.gz
- [bug] Fixed more un-intuitivenesses in CTEs
which prevented referring to a CTE in a union of itself without it being aliased. CTEs now render uniquely on name, rendering the outermost CTE of a given name only - all other references are rendered just as the name. This even includes other CTE/SELECTs that refer to different versions of the same CTE object, such as a SELECT or a UNION ALL of that SELECT. We are somewhat loosening the usual link between object identity and lexical identity in this case. A true name conflict between two unrelated CTEs now raises an error.
-rw-r--r--CHANGES15
-rw-r--r--lib/sqlalchemy/sql/compiler.py317
-rw-r--r--lib/sqlalchemy/sql/expression.py501
-rw-r--r--test/sql/test_cte.py179
4 files changed, 601 insertions, 411 deletions
diff --git a/CHANGES b/CHANGES
index 19e4ad512..72787307f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -342,6 +342,21 @@ are also present in 0.8.
positional binds + CTE support.
[ticket:2521]
+ - [bug] Fixed more un-intuitivenesses in CTEs
+ which prevented referring to a CTE in a union
+ of itself without it being aliased.
+ CTEs now render uniquely
+ on name, rendering the outermost CTE of a given
+ name only - all other references are rendered
+ just as the name. This even includes other
+ CTE/SELECTs that refer to different versions
+ of the same CTE object, such as a SELECT
+ or a UNION ALL of that SELECT. We are
+ somewhat loosening the usual link between object
+ identity and lexical identity in this case.
+ A true name conflict between two unrelated
+ CTEs now raises an error.
+
- [bug] quoting is applied to the column names
inside the WITH RECURSIVE clause of a
common table expression according to the
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 6fdb943d0..979c88e4b 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -17,7 +17,7 @@ strings
:class:`~sqlalchemy.sql.compiler.GenericTypeCompiler` - renders
type specification strings.
-To generate user-defined SQL strings, see
+To generate user-defined SQL strings, see
:module:`~sqlalchemy.ext.compiler`.
"""
@@ -215,7 +215,7 @@ class SQLCompiler(engine.Compiled):
driver/DB enforces this
"""
- def __init__(self, dialect, statement, column_keys=None,
+ def __init__(self, dialect, statement, column_keys=None,
inline=False, **kwargs):
"""Construct a new ``DefaultCompiler`` object.
@@ -259,11 +259,7 @@ class SQLCompiler(engine.Compiled):
self.positiontup = []
self.bindtemplate = BIND_TEMPLATES[dialect.paramstyle]
- # collect CTEs to tack on top of a SELECT
- self.ctes = util.OrderedDict()
- self.ctes_recursive = False
- if self.positional:
- self.cte_positional = []
+ self.ctes = None
# an IdentifierPreparer that formats the quoting of identifiers
self.preparer = dialect.identifier_preparer
@@ -282,11 +278,25 @@ class SQLCompiler(engine.Compiled):
if self.positional and dialect.paramstyle == 'numeric':
self._apply_numbered_params()
+ @util.memoized_instancemethod
+ def _init_cte_state(self):
+ """Initialize collections related to CTEs only if
+ a CTE is located, to save on the overhead of
+ these collections otherwise.
+
+ """
+ # collect CTEs to tack on top of a SELECT
+ self.ctes = util.OrderedDict()
+ self.ctes_by_name = {}
+ self.ctes_recursive = False
+ if self.positional:
+ self.cte_positional = []
+
def _apply_numbered_params(self):
poscount = itertools.count(1)
self.string = re.sub(
- r'\[_POSITION\]',
- lambda m:str(util.next(poscount)),
+ r'\[_POSITION\]',
+ lambda m:str(util.next(poscount)),
self.string)
@util.memoized_property
@@ -320,11 +330,11 @@ class SQLCompiler(engine.Compiled):
if _group_number:
raise exc.InvalidRequestError(
"A value is required for bind parameter %r, "
- "in parameter group %d" %
+ "in parameter group %d" %
(bindparam.key, _group_number))
else:
raise exc.InvalidRequestError(
- "A value is required for bind parameter %r"
+ "A value is required for bind parameter %r"
% bindparam.key)
else:
pd[name] = bindparam.effective_value
@@ -336,18 +346,18 @@ class SQLCompiler(engine.Compiled):
if _group_number:
raise exc.InvalidRequestError(
"A value is required for bind parameter %r, "
- "in parameter group %d" %
+ "in parameter group %d" %
(bindparam.key, _group_number))
else:
raise exc.InvalidRequestError(
- "A value is required for bind parameter %r"
+ "A value is required for bind parameter %r"
% bindparam.key)
pd[self.bind_names[bindparam]] = bindparam.effective_value
return pd
@property
def params(self):
- """Return the bind param dictionary embedded into this
+ """Return the bind param dictionary embedded into this
compiled object, for those values that are present."""
return self.construct_params(_check=False)
@@ -363,8 +373,8 @@ class SQLCompiler(engine.Compiled):
def visit_grouping(self, grouping, asfrom=False, **kwargs):
return "(" + grouping.element._compiler_dispatch(self, **kwargs) + ")"
- def visit_label(self, label, result_map=None,
- within_label_clause=False,
+ def visit_label(self, label, result_map=None,
+ within_label_clause=False,
within_columns_clause=False, **kw):
# only render labels within the columns clause
# or ORDER BY clause of a select. dialect-specific compilers
@@ -376,23 +386,23 @@ class SQLCompiler(engine.Compiled):
labelname = label.name
if result_map is not None:
- result_map[labelname
- if self.dialect.case_sensitive
+ result_map[labelname
+ if self.dialect.case_sensitive
else labelname.lower()] = (
- label.name,
- (label, label.element, labelname, ) +
+ label.name,
+ (label, label.element, labelname, ) +
label._alt_names,
label.type)
- return label.element._compiler_dispatch(self,
+ return label.element._compiler_dispatch(self,
within_columns_clause=True,
- within_label_clause=True,
+ within_label_clause=True,
**kw) + \
OPERATORS[operators.as_] + \
self.preparer.format_label(label, labelname)
else:
- return label.element._compiler_dispatch(self,
- within_columns_clause=False,
+ return label.element._compiler_dispatch(self,
+ within_columns_clause=False,
**kw)
def visit_column(self, column, result_map=None, **kwargs):
@@ -406,10 +416,10 @@ class SQLCompiler(engine.Compiled):
name = self._truncated_identifier("colident", name)
if result_map is not None:
- result_map[name
- if self.dialect.case_sensitive
- else name.lower()] = (orig_name,
- (column, name, column.key),
+ result_map[name
+ if self.dialect.case_sensitive
+ else name.lower()] = (orig_name,
+ (column, name, column.key),
column.type)
if is_literal:
@@ -423,7 +433,7 @@ class SQLCompiler(engine.Compiled):
else:
if table.schema:
schema_prefix = self.preparer.quote_schema(
- table.schema,
+ table.schema,
table.quote_schema) + '.'
else:
schema_prefix = ''
@@ -456,8 +466,8 @@ class SQLCompiler(engine.Compiled):
def visit_textclause(self, textclause, **kwargs):
if textclause.typemap is not None:
for colname, type_ in textclause.typemap.iteritems():
- self.result_map[colname
- if self.dialect.case_sensitive
+ self.result_map[colname
+ if self.dialect.case_sensitive
else colname.lower()] = \
(colname, None, type_)
@@ -490,8 +500,8 @@ class SQLCompiler(engine.Compiled):
else:
sep = OPERATORS[clauselist.operator]
return sep.join(
- s for s in
- (c._compiler_dispatch(self, **kwargs)
+ s for s in
+ (c._compiler_dispatch(self, **kwargs)
for c in clauselist.clauses)
if s)
@@ -531,13 +541,13 @@ class SQLCompiler(engine.Compiled):
def visit_extract(self, extract, **kwargs):
field = self.extract_map.get(extract.field, extract.field)
- return "EXTRACT(%s FROM %s)" % (field,
+ return "EXTRACT(%s FROM %s)" % (field,
extract.expr._compiler_dispatch(self, **kwargs))
def visit_function(self, func, result_map=None, **kwargs):
if result_map is not None:
- result_map[func.name
- if self.dialect.case_sensitive
+ result_map[func.name
+ if self.dialect.case_sensitive
else func.name.lower()] = \
(func.name, None, func.type)
@@ -560,7 +570,7 @@ class SQLCompiler(engine.Compiled):
def function_argspec(self, func, **kwargs):
return func.clause_expr._compiler_dispatch(self, **kwargs)
- def visit_compound_select(self, cs, asfrom=False,
+ def visit_compound_select(self, cs, asfrom=False,
parens=True, compound_index=1, **kwargs):
entry = self.stack and self.stack[-1] or {}
self.stack.append({'from':entry.get('from', None), 'iswrapper':True})
@@ -568,8 +578,8 @@ class SQLCompiler(engine.Compiled):
keyword = self.compound_keywords.get(cs.keyword)
text = (" " + keyword + " ").join(
- (c._compiler_dispatch(self,
- asfrom=asfrom, parens=False,
+ (c._compiler_dispatch(self,
+ asfrom=asfrom, parens=False,
compound_index=i, **kwargs)
for i, c in enumerate(cs.selects))
)
@@ -610,8 +620,8 @@ class SQLCompiler(engine.Compiled):
return self._operator_dispatch(binary.operator,
binary,
- lambda opstr: binary.left._compiler_dispatch(self, **kw) +
- opstr +
+ lambda opstr: binary.left._compiler_dispatch(self, **kw) +
+ opstr +
binary.right._compiler_dispatch(
self, **kw),
**kw
@@ -620,36 +630,36 @@ class SQLCompiler(engine.Compiled):
def visit_like_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return '%s LIKE %s' % (
- binary.left._compiler_dispatch(self, **kw),
+ binary.left._compiler_dispatch(self, **kw),
binary.right._compiler_dispatch(self, **kw)) \
- + (escape and
+ + (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
def visit_notlike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return '%s NOT LIKE %s' % (
- binary.left._compiler_dispatch(self, **kw),
+ binary.left._compiler_dispatch(self, **kw),
binary.right._compiler_dispatch(self, **kw)) \
- + (escape and
+ + (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
def visit_ilike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return 'lower(%s) LIKE lower(%s)' % (
- binary.left._compiler_dispatch(self, **kw),
+ binary.left._compiler_dispatch(self, **kw),
binary.right._compiler_dispatch(self, **kw)) \
- + (escape and
+ + (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
def visit_notilike_op(self, binary, **kw):
escape = binary.modifiers.get("escape", None)
return 'lower(%s) NOT LIKE lower(%s)' % (
- binary.left._compiler_dispatch(self, **kw),
+ binary.left._compiler_dispatch(self, **kw),
binary.right._compiler_dispatch(self, **kw)) \
- + (escape and
+ + (escape and
(' ESCAPE ' + self.render_literal_value(escape, None))
or '')
@@ -693,7 +703,7 @@ class SQLCompiler(engine.Compiled):
"bindparam() name '%s' is reserved "
"for automatic usage in the VALUES or SET "
"clause of this "
- "insert/update statement. Please use a "
+ "insert/update statement. Please use a "
"name other than column name when using bindparam() "
"with insert() or update() (for example, 'b_%s')."
% (bindparam.key, bindparam.key)
@@ -771,7 +781,7 @@ class SQLCompiler(engine.Compiled):
self.anon_map[derived] = anonymous_counter + 1
return derived + "_" + str(anonymous_counter)
- def bindparam_string(self, name, quote=None,
+ def bindparam_string(self, name, quote=None,
positional_names=None, **kw):
if self.positional:
if positional_names is not None:
@@ -780,8 +790,10 @@ class SQLCompiler(engine.Compiled):
self.positiontup.append(name)
return self.bindtemplate % {'name':name}
- def visit_cte(self, cte, asfrom=False, ashint=False,
- fromhints=None, **kwargs):
+ def visit_cte(self, cte, asfrom=False, ashint=False,
+ fromhints=None,
+ **kwargs):
+ self._init_cte_state()
if self.positional:
kwargs['positional_names'] = self.cte_positional
@@ -790,6 +802,25 @@ class SQLCompiler(engine.Compiled):
else:
cte_name = cte.name
+ if cte_name in self.ctes_by_name:
+ existing_cte = self.ctes_by_name[cte_name]
+ # we've generated a same-named CTE that we are enclosed in,
+ # or this is the same CTE. just return the name.
+ if cte in existing_cte._restates or cte is existing_cte:
+ return cte_name
+ elif existing_cte in cte._restates:
+ # we've generated a same-named CTE that is
+ # enclosed in us - we take precedence, so
+ # discard the text for the "inner".
+ del self.ctes[existing_cte]
+ else:
+ raise exc.CompileError(
+ "Multiple, unrelated CTEs found with "
+ "the same name: %r" %
+ cte_name)
+
+ self.ctes_by_name[cte_name] = cte
+
if cte.cte_alias:
if isinstance(cte.cte_alias, sql._truncated_label):
cte_alias = self._truncated_identifier("alias", cte.cte_alias)
@@ -806,12 +837,12 @@ class SQLCompiler(engine.Compiled):
col_source = cte.original.selects[0]
else:
assert False
- recur_cols = [c for c in
+ recur_cols = [c for c in
util.unique_list(col_source.inner_columns)
if c is not None]
text += "(%s)" % (", ".join(
- self.preparer.format_column(ident)
+ self.preparer.format_column(ident)
for ident in recur_cols))
text += " AS \n" + \
cte.original._compiler_dispatch(
@@ -826,7 +857,7 @@ class SQLCompiler(engine.Compiled):
return self.preparer.format_alias(cte, cte_name)
return text
- def visit_alias(self, alias, asfrom=False, ashint=False,
+ def visit_alias(self, alias, asfrom=False, ashint=False,
iscrud=False,
fromhints=None, **kwargs):
if asfrom or ashint:
@@ -838,13 +869,13 @@ class SQLCompiler(engine.Compiled):
if ashint:
return self.preparer.format_alias(alias, alias_name)
elif asfrom:
- ret = alias.original._compiler_dispatch(self,
+ ret = alias.original._compiler_dispatch(self,
asfrom=True, **kwargs) + \
" AS " + \
self.preparer.format_alias(alias, alias_name)
if fromhints and alias in fromhints:
- ret = self.format_from_hint_text(ret, alias,
+ ret = self.format_from_hint_text(ret, alias,
fromhints[alias], iscrud)
return ret
@@ -861,8 +892,8 @@ class SQLCompiler(engine.Compiled):
select.use_labels and \
column._label:
return _CompileLabel(
- column,
- column._label,
+ column,
+ column._label,
alt_names=(column._key_label, )
)
@@ -872,9 +903,9 @@ class SQLCompiler(engine.Compiled):
not column.is_literal and \
column.table is not None and \
not isinstance(column.table, sql.Select):
- return _CompileLabel(column, sql._as_truncated(column.name),
+ return _CompileLabel(column, sql._as_truncated(column.name),
alt_names=(column.key,))
- elif not isinstance(column,
+ elif not isinstance(column,
(sql._UnaryExpression, sql._TextClause)) \
and (not hasattr(column, 'name') or \
isinstance(column, sql.Function)):
@@ -897,9 +928,9 @@ class SQLCompiler(engine.Compiled):
def get_crud_hint_text(self, table, text):
return None
- def visit_select(self, select, asfrom=False, parens=True,
- iswrapper=False, fromhints=None,
- compound_index=1,
+ def visit_select(self, select, asfrom=False, parens=True,
+ iswrapper=False, fromhints=None,
+ compound_index=1,
positional_names=None, **kwargs):
entry = self.stack and self.stack[-1] or {}
@@ -919,7 +950,7 @@ class SQLCompiler(engine.Compiled):
: iswrapper})
if compound_index==1 and not entry or entry.get('iswrapper', False):
- column_clause_args = {'result_map':self.result_map,
+ column_clause_args = {'result_map':self.result_map,
'positional_names':positional_names}
else:
column_clause_args = {'positional_names':positional_names}
@@ -930,7 +961,7 @@ class SQLCompiler(engine.Compiled):
self.label_select_column(select, co, asfrom=asfrom).\
_compiler_dispatch(self,
within_columns_clause=True,
- **column_clause_args)
+ **column_clause_args)
for co in util.unique_list(select.inner_columns)
]
if c is not None
@@ -943,9 +974,9 @@ class SQLCompiler(engine.Compiled):
(from_, hinttext % {
'name':from_._compiler_dispatch(
self, ashint=True)
- })
- for (from_, dialect), hinttext in
- select._hints.iteritems()
+ })
+ for (from_, dialect), hinttext in
+ select._hints.iteritems()
if dialect in ('*', self.dialect.name)
])
hint_text = self.get_select_hint_text(byfrom)
@@ -954,7 +985,7 @@ class SQLCompiler(engine.Compiled):
if select._prefixes:
text += " ".join(
- x._compiler_dispatch(self, **kwargs)
+ x._compiler_dispatch(self, **kwargs)
for x in select._prefixes) + " "
text += self.get_select_precolumns(select)
text += ', '.join(inner_columns)
@@ -963,13 +994,13 @@ class SQLCompiler(engine.Compiled):
text += " \nFROM "
if select._hints:
- text += ', '.join([f._compiler_dispatch(self,
- asfrom=True, fromhints=byfrom,
- **kwargs)
+ text += ', '.join([f._compiler_dispatch(self,
+ asfrom=True, fromhints=byfrom,
+ **kwargs)
for f in froms])
else:
- text += ', '.join([f._compiler_dispatch(self,
- asfrom=True, **kwargs)
+ text += ', '.join([f._compiler_dispatch(self,
+ asfrom=True, **kwargs)
for f in froms])
else:
text += self.default_from()
@@ -1054,7 +1085,7 @@ class SQLCompiler(engine.Compiled):
text += " OFFSET " + self.process(sql.literal(select._offset))
return text
- def visit_table(self, table, asfrom=False, iscrud=False, ashint=False,
+ def visit_table(self, table, asfrom=False, iscrud=False, ashint=False,
fromhints=None, **kwargs):
if asfrom or ashint:
if getattr(table, "schema", None):
@@ -1065,7 +1096,7 @@ class SQLCompiler(engine.Compiled):
else:
ret = self.preparer.quote(table.name, table.quote)
if fromhints and table in fromhints:
- ret = self.format_from_hint_text(ret, table,
+ ret = self.format_from_hint_text(ret, table,
fromhints[table], iscrud)
return ret
else:
@@ -1073,10 +1104,10 @@ class SQLCompiler(engine.Compiled):
def visit_join(self, join, asfrom=False, **kwargs):
return (
- join.left._compiler_dispatch(self, asfrom=True, **kwargs) +
- (join.isouter and " LEFT OUTER JOIN " or " JOIN ") +
- join.right._compiler_dispatch(self, asfrom=True, **kwargs) +
- " ON " +
+ join.left._compiler_dispatch(self, asfrom=True, **kwargs) +
+ (join.isouter and " LEFT OUTER JOIN " or " JOIN ") +
+ join.right._compiler_dispatch(self, asfrom=True, **kwargs) +
+ " ON " +
join.onclause._compiler_dispatch(self, **kwargs)
)
@@ -1088,7 +1119,7 @@ class SQLCompiler(engine.Compiled):
not self.dialect.supports_default_values and \
not self.dialect.supports_empty_insert:
raise exc.CompileError("The version of %s you are using does "
- "not support empty inserts." %
+ "not support empty inserts." %
self.dialect.name)
preparer = self.preparer
@@ -1107,14 +1138,14 @@ class SQLCompiler(engine.Compiled):
if insert_stmt._hints:
dialect_hints = dict([
(table, hint_text)
- for (table, dialect), hint_text in
+ for (table, dialect), hint_text in
insert_stmt._hints.items()
if dialect in ('*', self.dialect.name)
])
if insert_stmt.table in dialect_hints:
table_text = self.format_from_hint_text(
table_text,
- insert_stmt.table,
+ insert_stmt.table,
dialect_hints[insert_stmt.table],
True
)
@@ -1148,7 +1179,7 @@ class SQLCompiler(engine.Compiled):
"""Provide a hook for MySQL to add LIMIT to the UPDATE"""
return None
- def update_tables_clause(self, update_stmt, from_table,
+ def update_tables_clause(self, update_stmt, from_table,
extra_froms, **kw):
"""Provide a hook to override the initial table clause
in an UPDATE statement.
@@ -1156,22 +1187,22 @@ class SQLCompiler(engine.Compiled):
MySQL overrides this.
"""
- return from_table._compiler_dispatch(self, asfrom=True,
+ return from_table._compiler_dispatch(self, asfrom=True,
iscrud=True, **kw)
- def update_from_clause(self, update_stmt,
- from_table, extra_froms,
+ def update_from_clause(self, update_stmt,
+ from_table, extra_froms,
from_hints,
**kw):
- """Provide a hook to override the generation of an
+ """Provide a hook to override the generation of an
UPDATE..FROM clause.
MySQL and MSSQL override this.
"""
return "FROM " + ', '.join(
- t._compiler_dispatch(self, asfrom=True,
- fromhints=from_hints, **kw)
+ t._compiler_dispatch(self, asfrom=True,
+ fromhints=from_hints, **kw)
for t in extra_froms)
def visit_update(self, update_stmt, **kw):
@@ -1190,14 +1221,14 @@ class SQLCompiler(engine.Compiled):
if update_stmt._hints:
dialect_hints = dict([
(table, hint_text)
- for (table, dialect), hint_text in
+ for (table, dialect), hint_text in
update_stmt._hints.items()
if dialect in ('*', self.dialect.name)
])
if update_stmt.table in dialect_hints:
table_text = self.format_from_hint_text(
table_text,
- update_stmt.table,
+ update_stmt.table,
dialect_hints[update_stmt.table],
True
)
@@ -1209,12 +1240,12 @@ class SQLCompiler(engine.Compiled):
text += ' SET '
if extra_froms and self.render_table_with_column_in_update_from:
text += ', '.join(
- self.visit_column(c[0]) +
+ self.visit_column(c[0]) +
'=' + c[1] for c in colparams
)
else:
text += ', '.join(
- self.preparer.quote(c[0].name, c[0].quote) +
+ self.preparer.quote(c[0].name, c[0].quote) +
'=' + c[1] for c in colparams
)
@@ -1226,9 +1257,9 @@ class SQLCompiler(engine.Compiled):
if extra_froms:
extra_from_text = self.update_from_clause(
- update_stmt,
- update_stmt.table,
- extra_froms,
+ update_stmt,
+ update_stmt.table,
+ extra_froms,
dialect_hints, **kw)
if extra_from_text:
text += " " + extra_from_text
@@ -1249,7 +1280,7 @@ class SQLCompiler(engine.Compiled):
return text
def _create_crud_bind_param(self, col, value, required=False):
- bindparam = sql.bindparam(col.key, value,
+ bindparam = sql.bindparam(col.key, value,
type_=col.type, required=required,
quote=col.quote)
bindparam._is_crud = True
@@ -1275,8 +1306,8 @@ class SQLCompiler(engine.Compiled):
# compiled params - return binds for all columns
if self.column_keys is None and stmt.parameters is None:
return [
- (c, self._create_crud_bind_param(c,
- None, required=True))
+ (c, self._create_crud_bind_param(c,
+ None, required=True))
for c in stmt.table.columns
]
@@ -1288,8 +1319,8 @@ class SQLCompiler(engine.Compiled):
parameters = {}
else:
parameters = dict((sql._column_as_key(key), required)
- for key in self.column_keys
- if not stmt.parameters or
+ for key in self.column_keys
+ if not stmt.parameters or
key not in stmt.parameters)
if stmt.parameters is not None:
@@ -1310,7 +1341,7 @@ class SQLCompiler(engine.Compiled):
postfetch_lastrowid = need_pks and self.dialect.postfetch_lastrowid
check_columns = {}
- # special logic that only occurs for multi-table UPDATE
+ # special logic that only occurs for multi-table UPDATE
# statements
if extra_tables and stmt.parameters:
assert self.isupdate
@@ -1329,7 +1360,7 @@ class SQLCompiler(engine.Compiled):
value = self.process(value.self_group())
values.append((c, value))
# determine tables which are actually
- # to be updated - process onupdate and
+ # to be updated - process onupdate and
# server_onupdate for these
for t in affected_tables:
for c in t.c:
@@ -1350,7 +1381,7 @@ class SQLCompiler(engine.Compiled):
self.postfetch.append(c)
# iterating through columns at the top to maintain ordering.
- # otherwise we might iterate through individual sets of
+ # otherwise we might iterate through individual sets of
# "defaults", "primary key cols", etc.
for c in stmt.table.columns:
if c.key in parameters and c.key not in check_columns:
@@ -1370,8 +1401,8 @@ class SQLCompiler(engine.Compiled):
if c.primary_key and \
need_pks and \
(
- implicit_returning or
- not postfetch_lastrowid or
+ implicit_returning or
+ not postfetch_lastrowid or
c is not stmt.table._autoincrement_column
):
@@ -1457,7 +1488,7 @@ class SQLCompiler(engine.Compiled):
).difference(check_columns)
if check:
raise exc.CompileError(
- "Unconsumed column names: %s" %
+ "Unconsumed column names: %s" %
(", ".join(check))
)
@@ -1468,13 +1499,13 @@ class SQLCompiler(engine.Compiled):
self.isdelete = True
text = "DELETE FROM "
- table_text = delete_stmt.table._compiler_dispatch(self,
+ table_text = delete_stmt.table._compiler_dispatch(self,
asfrom=True, iscrud=True)
if delete_stmt._hints:
dialect_hints = dict([
(table, hint_text)
- for (table, dialect), hint_text in
+ for (table, dialect), hint_text in
delete_stmt._hints.items()
if dialect in ('*', self.dialect.name)
])
@@ -1498,8 +1529,8 @@ class SQLCompiler(engine.Compiled):
delete_stmt, delete_stmt._returning)
if delete_stmt._whereclause is not None:
- text += " WHERE "
- text += delete_stmt._whereclause._compiler_dispatch(self)
+ text += " WHERE "
+ text += delete_stmt._whereclause._compiler_dispatch(self)
if self.returning and not self.returning_precedes_values:
text += " " + self.returning_clause(
@@ -1580,7 +1611,7 @@ class DDLCompiler(engine.Compiled):
text += separator
separator = ", \n"
text += "\t" + self.get_column_specification(
- column,
+ column,
first_pk=column.primary_key and \
not first_pk
)
@@ -1592,16 +1623,16 @@ class DDLCompiler(engine.Compiled):
text += " " + const
except exc.CompileError, ce:
# Py3K
- #raise exc.CompileError("(in table '%s', column '%s'): %s"
+ #raise exc.CompileError("(in table '%s', column '%s'): %s"
# % (
- # table.description,
- # column.name,
+ # table.description,
+ # column.name,
# ce.args[0]
# )) from ce
# Py2K
- raise exc.CompileError("(in table '%s', column '%s'): %s"
+ raise exc.CompileError("(in table '%s', column '%s'): %s"
% (
- table.description,
+ table.description,
column.name,
ce.args[0]
)), None, sys.exc_info()[2]
@@ -1622,17 +1653,17 @@ class DDLCompiler(engine.Compiled):
if table.primary_key:
constraints.append(table.primary_key)
- constraints.extend([c for c in table._sorted_constraints
+ constraints.extend([c for c in table._sorted_constraints
if c is not table.primary_key])
return ", \n\t".join(p for p in
- (self.process(constraint)
- for constraint in constraints
+ (self.process(constraint)
+ for constraint in constraints
if (
constraint._create_rule is None or
constraint._create_rule(self))
and (
- not self.dialect.supports_alter or
+ not self.dialect.supports_alter or
not getattr(constraint, 'use_alter', False)
)) if p is not None
)
@@ -1660,7 +1691,7 @@ class DDLCompiler(engine.Compiled):
if index.unique:
text += "UNIQUE "
text += "INDEX %s ON %s (%s)" \
- % (preparer.quote(self._index_identifier(index.name),
+ % (preparer.quote(self._index_identifier(index.name),
index.quote),
preparer.format_table(index.table),
', '.join(preparer.quote(c.name, c.quote)
@@ -1787,7 +1818,7 @@ class DDLCompiler(engine.Compiled):
text += "CONSTRAINT %s " % \
self.preparer.format_constraint(constraint)
text += "UNIQUE (%s)" % (
- ', '.join(self.preparer.quote(c.name, c.quote)
+ ', '.join(self.preparer.quote(c.name, c.quote)
for c in constraint))
text += self.define_constraint_deferrability(constraint)
return text
@@ -1839,7 +1870,7 @@ class GenericTypeCompiler(engine.TypeCompiler):
{'precision': type_.precision}
else:
return "NUMERIC(%(precision)s, %(scale)s)" % \
- {'precision': type_.precision,
+ {'precision': type_.precision,
'scale' : type_.scale}
def visit_DECIMAL(self, type_):
@@ -1896,25 +1927,25 @@ class GenericTypeCompiler(engine.TypeCompiler):
def visit_large_binary(self, type_):
return self.visit_BLOB(type_)
- def visit_boolean(self, type_):
+ def visit_boolean(self, type_):
return self.visit_BOOLEAN(type_)
- def visit_time(self, type_):
+ def visit_time(self, type_):
return self.visit_TIME(type_)
- def visit_datetime(self, type_):
+ def visit_datetime(self, type_):
return self.visit_DATETIME(type_)
- def visit_date(self, type_):
+ def visit_date(self, type_):
return self.visit_DATE(type_)
- def visit_big_integer(self, type_):
+ def visit_big_integer(self, type_):
return self.visit_BIGINT(type_)
- def visit_small_integer(self, type_):
+ def visit_small_integer(self, type_):
return self.visit_SMALLINT(type_)
- def visit_integer(self, type_):
+ def visit_integer(self, type_):
return self.visit_INTEGER(type_)
def visit_real(self, type_):
@@ -1923,19 +1954,19 @@ class GenericTypeCompiler(engine.TypeCompiler):
def visit_float(self, type_):
return self.visit_FLOAT(type_)
- def visit_numeric(self, type_):
+ def visit_numeric(self, type_):
return self.visit_NUMERIC(type_)
- def visit_string(self, type_):
+ def visit_string(self, type_):
return self.visit_VARCHAR(type_)
- def visit_unicode(self, type_):
+ def visit_unicode(self, type_):
return self.visit_VARCHAR(type_)
- def visit_text(self, type_):
+ def visit_text(self, type_):
return self.visit_TEXT(type_)
- def visit_unicode_text(self, type_):
+ def visit_unicode_text(self, type_):
return self.visit_TEXT(type_)
def visit_enum(self, type_):
@@ -1959,7 +1990,7 @@ class IdentifierPreparer(object):
illegal_initial_characters = ILLEGAL_INITIAL_CHARACTERS
- def __init__(self, dialect, initial_quote='"',
+ def __init__(self, dialect, initial_quote='"',
final_quote=None, escape_quote='"', omit_schema=False):
"""Construct a new ``IdentifierPreparer`` object.
@@ -2023,7 +2054,7 @@ class IdentifierPreparer(object):
def quote_schema(self, schema, force):
"""Quote a schema.
- Subclasses should override this to provide database-dependent
+ Subclasses should override this to provide database-dependent
quoting behavior.
"""
return self.quote(schema, force)
@@ -2080,7 +2111,7 @@ class IdentifierPreparer(object):
return self.quote(name, quote)
- def format_column(self, column, use_table=False,
+ def format_column(self, column, use_table=False,
name=None, table_name=None):
"""Prepare a quoted column name."""
@@ -2089,7 +2120,7 @@ class IdentifierPreparer(object):
if not getattr(column, 'is_literal', False):
if use_table:
return self.format_table(
- column.table, use_schema=False,
+ column.table, use_schema=False,
name=table_name) + "." + \
self.quote(name, column.quote)
else:
diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py
index 4be8a976d..631a1b205 100644
--- a/lib/sqlalchemy/sql/expression.py
+++ b/lib/sqlalchemy/sql/expression.py
@@ -114,20 +114,20 @@ def outerjoin(left, right, onclause=None):
The returned object is an instance of :class:`.Join`.
- Similar functionality is also available via the
- :meth:`~.FromClause.outerjoin()` method on any
+ Similar functionality is also available via the
+ :meth:`~.FromClause.outerjoin()` method on any
:class:`.FromClause`.
:param left: The left side of the join.
:param right: The right side of the join.
- :param onclause: Optional criterion for the ``ON`` clause, is
- derived from foreign key relationships established between
+ :param onclause: Optional criterion for the ``ON`` clause, is
+ derived from foreign key relationships established between
left and right otherwise.
- To chain joins together, use the :meth:`.FromClause.join` or
- :meth:`.FromClause.outerjoin` methods on the resulting
+ To chain joins together, use the :meth:`.FromClause.join` or
+ :meth:`.FromClause.outerjoin` methods on the resulting
:class:`.Join` object.
"""
@@ -138,20 +138,20 @@ def join(left, right, onclause=None, isouter=False):
The returned object is an instance of :class:`.Join`.
- Similar functionality is also available via the
- :meth:`~.FromClause.join()` method on any
+ Similar functionality is also available via the
+ :meth:`~.FromClause.join()` method on any
:class:`.FromClause`.
:param left: The left side of the join.
:param right: The right side of the join.
- :param onclause: Optional criterion for the ``ON`` clause, is
- derived from foreign key relationships established between
+ :param onclause: Optional criterion for the ``ON`` clause, is
+ derived from foreign key relationships established between
left and right otherwise.
- To chain joins together, use the :meth:`.FromClause.join` or
- :meth:`.FromClause.outerjoin` methods on the resulting
+ To chain joins together, use the :meth:`.FromClause.join` or
+ :meth:`.FromClause.outerjoin` methods on the resulting
:class:`.Join` object.
@@ -208,7 +208,7 @@ def select(columns=None, whereclause=None, from_obj=[], **kwargs):
to set the autocommit option.
:param bind=None:
- an :class:`~.base.Engine` or :class:`~.base.Connection` instance
+ an :class:`~.base.Engine` or :class:`~.base.Connection` instance
to which the
resulting :class:`.Select` object will be bound. The :class:`.Select`
object will otherwise automatically bind to whatever
@@ -236,7 +236,7 @@ def select(columns=None, whereclause=None, from_obj=[], **kwargs):
``distinct`` is also available via the :meth:`~.Select.distinct`
generative method.
- .. note::
+ .. note::
The ``distinct`` keyword's acceptance of a string
argument for usage with MySQL is deprecated. Use
@@ -249,7 +249,7 @@ def select(columns=None, whereclause=None, from_obj=[], **kwargs):
Certain database dialects also support
alternate values for this parameter:
- * With the MySQL dialect, the value ``"read"`` translates to
+ * With the MySQL dialect, the value ``"read"`` translates to
``LOCK IN SHARE MODE``.
* With the Oracle and Postgresql dialects, the value ``"nowait"``
translates to ``FOR UPDATE NOWAIT``.
@@ -306,7 +306,7 @@ def select(columns=None, whereclause=None, from_obj=[], **kwargs):
**kwargs)
def subquery(alias, *args, **kwargs):
- """Return an :class:`.Alias` object derived
+ """Return an :class:`.Alias` object derived
from a :class:`.Select`.
name
@@ -321,7 +321,7 @@ def subquery(alias, *args, **kwargs):
return Select(*args, **kwargs).alias(alias)
def insert(table, values=None, inline=False, **kwargs):
- """Represent an ``INSERT`` statement via the :class:`.Insert` SQL
+ """Represent an ``INSERT`` statement via the :class:`.Insert` SQL
construct.
Similar functionality is available via the :meth:`~.TableClause.insert` method on
@@ -370,7 +370,7 @@ def insert(table, values=None, inline=False, **kwargs):
return Insert(table, values, inline=inline, **kwargs)
def update(table, whereclause=None, values=None, inline=False, **kwargs):
- """Represent an ``UPDATE`` statement via the :class:`.Update` SQL
+ """Represent an ``UPDATE`` statement via the :class:`.Update` SQL
construct.
E.g.::
@@ -393,12 +393,12 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs):
:param whereclause: Optional SQL expression describing the ``WHERE``
condition of the ``UPDATE`` statement. Modern applications
- may prefer to use the generative :meth:`~Update.where()`
+ may prefer to use the generative :meth:`~Update.where()`
method to specify the ``WHERE`` clause.
The WHERE clause can refer to multiple tables.
For databases which support this, an ``UPDATE FROM`` clause will
- be generated, or on MySQL, a multi-table update. The statement
+ be generated, or on MySQL, a multi-table update. The statement
will fail on databases that don't have support for multi-table
update statements. A SQL-standard method of referring to
additional tables in the WHERE clause is to use a correlated
@@ -416,20 +416,20 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs):
:param values:
Optional dictionary which specifies the ``SET`` conditions of the
``UPDATE``. If left as ``None``, the ``SET``
- conditions are determined from those parameters passed to the
- statement during the execution and/or compilation of the
+ conditions are determined from those parameters passed to the
+ statement during the execution and/or compilation of the
statement. When compiled standalone without any parameters,
the ``SET`` clause generates for all columns.
- Modern applications may prefer to use the generative
- :meth:`.Update.values` method to set the values of the
+ Modern applications may prefer to use the generative
+ :meth:`.Update.values` method to set the values of the
UPDATE statement.
:param inline:
- if True, SQL defaults present on :class:`.Column` objects via
+ if True, SQL defaults present on :class:`.Column` objects via
the ``default`` keyword will be compiled 'inline' into the statement
and not pre-executed. This means that their values will not
- be available in the dictionary returned from
+ be available in the dictionary returned from
:meth:`.ResultProxy.last_updated_params`.
If both ``values`` and compile-time bind parameters are present, the
@@ -441,7 +441,7 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs):
:class:`.Column`, normally but not necessarily equivalent to
its "name"). Normally, the
:class:`.Column` objects used here are expected to be
- part of the target :class:`.Table` that is the table
+ part of the target :class:`.Table` that is the table
to be updated. However when using MySQL, a multiple-table
UPDATE statement can refer to columns from any of
the tables referred to in the WHERE clause.
@@ -450,12 +450,12 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs):
* a literal data value (i.e. string, number, etc.)
* a SQL expression, such as a related :class:`.Column`,
- a scalar-returning :func:`.select` construct,
+ a scalar-returning :func:`.select` construct,
etc.
When combining :func:`.select` constructs within the values
clause of an :func:`.update` construct,
- the subquery represented by the :func:`.select` should be
+ the subquery represented by the :func:`.select` should be
*correlated* to the parent table, that is, providing criterion
which links the table inside the subquery to the outer table
being updated::
@@ -468,20 +468,20 @@ def update(table, whereclause=None, values=None, inline=False, **kwargs):
See also:
- :ref:`inserts_and_updates` - SQL Expression
+ :ref:`inserts_and_updates` - SQL Expression
Language Tutorial
"""
return Update(
- table,
- whereclause=whereclause,
- values=values,
- inline=inline,
+ table,
+ whereclause=whereclause,
+ values=values,
+ inline=inline,
**kwargs)
def delete(table, whereclause = None, **kwargs):
- """Represent a ``DELETE`` statement via the :class:`.Delete` SQL
+ """Represent a ``DELETE`` statement via the :class:`.Delete` SQL
construct.
Similar functionality is available via the :meth:`~.TableClause.delete` method on
@@ -582,7 +582,7 @@ def case(whens, value=None, else_=None):
when specified as strings, will be interpreted
as bound values. To specify textual SQL expressions
for these, use the :func:`literal_column`
- construct.
+ construct.
The expressions used for the WHEN criterion
may only be literal strings when "value" is
@@ -607,7 +607,7 @@ def case(whens, value=None, else_=None):
can be specified which determines the type of the :func:`case()` construct
overall::
- case([(orderline.c.qty > 100,
+ case([(orderline.c.qty > 100,
literal_column("'greaterthan100'", String)),
(orderline.c.qty > 10, literal_column("'greaterthan10'",
String))
@@ -653,8 +653,8 @@ def collate(expression, collation):
expr = _literal_as_binds(expression)
return _BinaryExpression(
- expr,
- _literal_as_text(collation),
+ expr,
+ _literal_as_text(collation),
operators.collate, type_=expr.type)
def exists(*args, **kwargs):
@@ -785,7 +785,7 @@ def alias(selectable, name=None):
with an alternate name assigned within SQL, typically using the ``AS``
clause when generated, e.g. ``SELECT * FROM table AS aliasname``.
- Similar functionality is available via the
+ Similar functionality is available via the
:meth:`~.FromClause.alias` method
available on all :class:`.FromClause` subclasses.
@@ -845,10 +845,10 @@ def tuple_(*expr):
.. warning::
- The composite IN construct is not supported by all backends,
+ The composite IN construct is not supported by all backends,
and is currently known to work on Postgresql and MySQL,
but not SQLite. Unsupported backends will raise
- a subclass of :class:`~sqlalchemy.exc.DBAPIError` when such
+ a subclass of :class:`~sqlalchemy.exc.DBAPIError` when such
an expression is invoked.
"""
@@ -884,7 +884,7 @@ def type_coerce(expr, type_):
conn.execute(
select([type_coerce(mytable.c.ident, AsGuid)]).\\
where(
- type_coerce(mytable.c.ident, AsGuid) ==
+ type_coerce(mytable.c.ident, AsGuid) ==
uuid.uuid3(uuid.NAMESPACE_URL, 'bar')
)
)
@@ -936,11 +936,11 @@ def column(text, type_=None):
from sqlalchemy.sql import table, column
- :param text: the name of the column. Quoting rules will be applied
+ :param text: the name of the column. Quoting rules will be applied
to the clause like any other column name. For textual column constructs
that are not to be quoted, use the :func:`literal_column` function.
- :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine` object
+ :param type\_: an optional :class:`~sqlalchemy.types.TypeEngine` object
which will provide result-set translation for this column.
See :class:`.ColumnClause` for further examples.
@@ -974,8 +974,8 @@ def table(name, *columns):
"""Represent a textual table clause.
The object returned is an instance of :class:`.TableClause`, which represents the
- "syntactical" portion of the schema-level :class:`~.schema.Table` object.
- It may be used to construct lightweight table constructs.
+ "syntactical" portion of the schema-level :class:`~.schema.Table` object.
+ It may be used to construct lightweight table constructs.
Note that the :func:`~.expression.table` function is not part of
the ``sqlalchemy`` namespace. It must be imported from the ``sql`` package::
@@ -991,7 +991,7 @@ def table(name, *columns):
"""
return TableClause(name, *columns)
-def bindparam(key, value=None, type_=None, unique=False, required=False,
+def bindparam(key, value=None, type_=None, unique=False, required=False,
quote=None, callable_=None):
"""Create a bind parameter clause with the given key.
@@ -1038,7 +1038,7 @@ def bindparam(key, value=None, type_=None, unique=False, required=False,
if isinstance(key, ColumnClause):
type_ = key.type
key = key.name
- return _BindParamClause(key, value, type_=type_,
+ return _BindParamClause(key, value, type_=type_,
callable_=callable_,
unique=unique, required=required,
quote=quote)
@@ -1066,8 +1066,8 @@ def text(text, bind=None, *args, **kwargs):
The advantages :func:`text` provides over a plain string are
backend-neutral support for bind parameters, per-statement
- execution options, as well as
- bind parameter and result-column typing behavior, allowing
+ execution options, as well as
+ bind parameter and result-column typing behavior, allowing
SQLAlchemy type constructs to play a role when executing
a statement that is specified literally.
@@ -1077,7 +1077,7 @@ def text(text, bind=None, *args, **kwargs):
t = text("SELECT * FROM users WHERE id=:user_id")
result = connection.execute(t, user_id=12)
- To invoke SQLAlchemy typing logic for bind parameters, the
+ To invoke SQLAlchemy typing logic for bind parameters, the
``bindparams`` list allows specification of :func:`bindparam`
constructs which specify the type for a given name::
@@ -1119,8 +1119,8 @@ def text(text, bind=None, *args, **kwargs):
Note that SQLAlchemy's usual "autocommit" behavior applies to
:func:`text` constructs - that is, statements which begin
- with a phrase such as ``INSERT``, ``UPDATE``, ``DELETE``,
- or a variety of other phrases specific to certain backends, will
+ with a phrase such as ``INSERT``, ``UPDATE``, ``DELETE``,
+ or a variety of other phrases specific to certain backends, will
be eligible for autocommit if no transaction is in progress.
:param text:
@@ -1146,7 +1146,7 @@ def text(text, bind=None, *args, **kwargs):
a dictionary mapping the names of columns represented in the
columns clause of a ``SELECT`` statement to type objects,
which will be used to perform post-processing on columns within
- the result set. This argument applies to any expression
+ the result set. This argument applies to any expression
that returns result sets.
"""
@@ -1189,14 +1189,14 @@ def null():
return _Null()
def true():
- """Return a :class:`_True` object, which compiles to ``true``, or the
+ """Return a :class:`_True` object, which compiles to ``true``, or the
boolean equivalent for the target dialect.
"""
return _True()
def false():
- """Return a :class:`_False` object, which compiles to ``false``, or the
+ """Return a :class:`_False` object, which compiles to ``false``, or the
boolean equivalent for the target dialect.
"""
@@ -1307,23 +1307,23 @@ class _truncated_label(unicode):
return self
# for backwards compatibility in case
-# someone is re-implementing the
+# someone is re-implementing the
# _truncated_identifier() sequence in a custom
# compiler
_generated_label = _truncated_label
class _anonymous_label(_truncated_label):
- """A unicode subclass used to identify anonymously
+ """A unicode subclass used to identify anonymously
generated names."""
def __add__(self, other):
return _anonymous_label(
- unicode(self) +
+ unicode(self) +
unicode(other))
def __radd__(self, other):
return _anonymous_label(
- unicode(other) +
+ unicode(other) +
unicode(self))
def apply_map(self, map_):
@@ -1332,7 +1332,7 @@ class _anonymous_label(_truncated_label):
def _as_truncated(value):
"""coerce the given value to :class:`._truncated_label`.
- Existing :class:`._truncated_label` and
+ Existing :class:`._truncated_label` and
:class:`._anonymous_label` objects are passed
unchanged.
"""
@@ -1362,7 +1362,7 @@ def _expand_cloned(elements):
return itertools.chain(*[x._cloned_set for x in elements])
def _select_iterables(elements):
- """expand tables into individual columns in the
+ """expand tables into individual columns in the
given list of column expressions.
"""
@@ -1492,8 +1492,8 @@ def _corresponding_column_or_error(fromclause, column,
raise exc.InvalidRequestError(
"Given column '%s', attached to table '%s', "
"failed to locate a corresponding column from table '%s'"
- %
- (column,
+ %
+ (column,
getattr(column, 'table', None),fromclause.description)
)
return c
@@ -1551,7 +1551,7 @@ class ClauseElement(Visitable):
def _constructor(self):
"""return the 'constructor' for this ClauseElement.
- This is for the purposes for creating a new object of
+ This is for the purposes for creating a new object of
this type. Usually, its just the element's __class__.
However, the "Annotated" version of the object overrides
to return the class of its proxied element.
@@ -1705,21 +1705,21 @@ class ClauseElement(Visitable):
def self_group(self, against=None):
"""Apply a 'grouping' to this :class:`.ClauseElement`.
- This method is overridden by subclasses to return a
+ This method is overridden by subclasses to return a
"grouping" construct, i.e. parenthesis. In particular
it's used by "binary" expressions to provide a grouping
- around themselves when placed into a larger expression,
+ around themselves when placed into a larger expression,
as well as by :func:`.select` constructs when placed into
- the FROM clause of another :func:`.select`. (Note that
- subqueries should be normally created using the
+ the FROM clause of another :func:`.select`. (Note that
+ subqueries should be normally created using the
:func:`.Select.alias` method, as many platforms require
nested SELECT statements to be named).
As expressions are composed together, the application of
- :meth:`self_group` is automatic - end-user code should never
+ :meth:`self_group` is automatic - end-user code should never
need to use this method directly. Note that SQLAlchemy's
- clause constructs take operator precedence into account -
- so parenthesis might not be needed, for example, in
+ clause constructs take operator precedence into account -
+ so parenthesis might not be needed, for example, in
an expression like ``x OR (y AND z)`` - AND takes precedence
over OR.
@@ -1829,8 +1829,8 @@ class ClauseElement(Visitable):
return self.negation_clause
else:
return _UnaryExpression(
- self.self_group(against=operators.inv),
- operator=operators.inv,
+ self.self_group(against=operators.inv),
+ operator=operators.inv,
negate=None)
def __repr__(self):
@@ -1859,7 +1859,7 @@ class _CompareMixin(ColumnOperators):
"""Defines comparison and math operations for :class:`.ClauseElement`
instances.
- See :class:`.ColumnOperators` and :class:`.Operators` for descriptions
+ See :class:`.ColumnOperators` and :class:`.Operators` for descriptions
of all operations.
"""
@@ -1881,16 +1881,16 @@ class _CompareMixin(ColumnOperators):
obj = self._check_literal(op, obj)
if reverse:
- return _BinaryExpression(obj,
- self,
- op,
- type_=sqltypes.BOOLEANTYPE,
+ return _BinaryExpression(obj,
+ self,
+ op,
+ type_=sqltypes.BOOLEANTYPE,
negate=negate, modifiers=kwargs)
else:
- return _BinaryExpression(self,
- obj,
- op,
- type_=sqltypes.BOOLEANTYPE,
+ return _BinaryExpression(self,
+ obj,
+ op,
+ type_=sqltypes.BOOLEANTYPE,
negate=negate, modifiers=kwargs)
def __operate(self, op, obj, reverse=False):
@@ -2015,7 +2015,7 @@ class _CompareMixin(ColumnOperators):
"""See :meth:`.ColumnOperators.endswith`."""
return self.__compare(
operators.like_op,
- literal_column("'%'", type_=sqltypes.String) +
+ literal_column("'%'", type_=sqltypes.String) +
self._check_literal(operators.like_op, other),
escape=escape)
@@ -2087,8 +2087,8 @@ class _CompareMixin(ColumnOperators):
return lambda other: self.__operate(operator, other)
def _bind_param(self, operator, obj):
- return _BindParamClause(None, obj,
- _compared_to_operator=operator,
+ return _BindParamClause(None, obj,
+ _compared_to_operator=operator,
_compared_to_type=self.type, unique=True)
def _check_literal(self, operator, other):
@@ -2160,7 +2160,7 @@ class ColumnElement(ClauseElement, _CompareMixin):
return s
def shares_lineage(self, othercolumn):
- """Return True if the given :class:`.ColumnElement`
+ """Return True if the given :class:`.ColumnElement`
has a common ancestor to this :class:`.ColumnElement`."""
return bool(self.proxy_set.intersection(othercolumn.proxy_set))
@@ -2184,7 +2184,7 @@ class ColumnElement(ClauseElement, _CompareMixin):
else:
key = name
co = ColumnClause(_as_truncated(name),
- selectable,
+ selectable,
type_=getattr(self,
'type', None))
co.proxies = [self]
@@ -2395,7 +2395,7 @@ class Selectable(ClauseElement):
__visit_name__ = 'selectable'
class FromClause(Selectable):
- """Represent an element that can be used within the ``FROM``
+ """Represent an element that can be used within the ``FROM``
clause of a ``SELECT`` statement.
"""
@@ -2404,7 +2404,7 @@ class FromClause(Selectable):
_hide_froms = []
quote = None
schema = None
- _memoized_property = util.group_expirable_memoized_property(["_columns"])
+ _memoized_property = util.group_expirable_memoized_property(["_columns"])
def count(self, whereclause=None, **params):
"""return a SELECT COUNT generated against this
@@ -2415,9 +2415,9 @@ class FromClause(Selectable):
else:
col = list(self.columns)[0]
return select(
- [func.count(col).label('tbl_row_count')],
- whereclause,
- from_obj=[self],
+ [func.count(col).label('tbl_row_count')],
+ whereclause,
+ from_obj=[self],
**params)
def select(self, whereclause=None, **params):
@@ -2459,22 +2459,22 @@ class FromClause(Selectable):
"""
# this is essentially an "identity" check in the base class.
- # Other constructs override this to traverse through
+ # Other constructs override this to traverse through
# contained elements.
return fromclause in self._cloned_set
def _is_lexical_equivalent(self, other):
"""Return True if this FromClause and the other represent
the same lexical identity.
-
- This tests if either one is a copy of the other, or
+
+ This tests if either one is a copy of the other, or
if they are the same via annotation identity.
"""
- return self._cloned_set.intersection(other._cloned_set)
+ return self._cloned_set.intersection(other._cloned_set)
def replace_selectable(self, old, alias):
- """replace all occurrences of FromClause 'old' with the given Alias
+ """replace all occurrences of FromClause 'old' with the given Alias
object, returning a copy of this :class:`.FromClause`.
"""
@@ -2632,9 +2632,9 @@ class _BindParamClause(ColumnElement):
__visit_name__ = 'bindparam'
quote = None
- def __init__(self, key, value, type_=None, unique=False,
+ def __init__(self, key, value, type_=None, unique=False,
callable_=None,
- isoutparam=False, required=False,
+ isoutparam=False, required=False,
quote=None,
_compared_to_operator=None,
_compared_to_type=None):
@@ -2671,7 +2671,7 @@ class _BindParamClause(ColumnElement):
already has been located within the containing
:class:`.ClauseElement`.
- :param quote:
+ :param quote:
True if this parameter name requires quoting and is not
currently known as a SQLAlchemy reserved word; this currently
only applies to the Oracle backend.
@@ -2696,7 +2696,7 @@ class _BindParamClause(ColumnElement):
# identity
self._identifying_key = self.key
- # key that was passed in the first place, used to
+ # key that was passed in the first place, used to
# generate new keys
self._orig_key = key or 'param'
@@ -2721,7 +2721,7 @@ class _BindParamClause(ColumnElement):
@property
def effective_value(self):
- """Return the value of this bound parameter,
+ """Return the value of this bound parameter,
taking into account if the ``callable`` parameter
was set.
@@ -2813,12 +2813,12 @@ class Executable(_Generative):
""" Set non-SQL options for the statement which take effect during
execution.
- Execution options can be set on a per-statement or
- per :class:`.Connection` basis. Additionally, the
+ Execution options can be set on a per-statement or
+ per :class:`.Connection` basis. Additionally, the
:class:`.Engine` and ORM :class:`~.orm.query.Query` objects provide access
to execution options which they in turn configure upon connections.
- The :meth:`execution_options` method is generative. A new
+ The :meth:`execution_options` method is generative. A new
instance of this statement is returned that contains the options::
statement = select([table.c.x, table.c.y])
@@ -2827,7 +2827,7 @@ class Executable(_Generative):
Note that only a subset of possible execution options can be applied
to a statement - these include "autocommit" and "stream_results",
but not "isolation_level" or "compiled_cache".
- See :meth:`.Connection.execution_options` for a full list of
+ See :meth:`.Connection.execution_options` for a full list of
possible options.
See also:
@@ -2872,7 +2872,7 @@ class Executable(_Generative):
@property
def bind(self):
- """Returns the :class:`.Engine` or :class:`.Connection` to
+ """Returns the :class:`.Engine` or :class:`.Connection` to
which this :class:`.Executable` is bound, or None if none found.
This is a traversal which checks locally, then
@@ -3135,12 +3135,12 @@ class _Case(ColumnElement):
if value is not None:
whenlist = [
- (_literal_as_binds(c).self_group(),
+ (_literal_as_binds(c).self_group(),
_literal_as_binds(r)) for (c, r) in whens
]
else:
whenlist = [
- (_no_literals(c).self_group(),
+ (_no_literals(c).self_group(),
_literal_as_binds(r)) for (c, r) in whens
]
@@ -3164,7 +3164,7 @@ class _Case(ColumnElement):
def _copy_internals(self, clone=_clone, **kw):
if self.value is not None:
self.value = clone(self.value, **kw)
- self.whens = [(clone(x, **kw), clone(y, **kw))
+ self.whens = [(clone(x, **kw), clone(y, **kw))
for x, y in self.whens]
if self.else_ is not None:
self.else_ = clone(self.else_, **kw)
@@ -3176,7 +3176,7 @@ class _Case(ColumnElement):
yield x
yield y
if self.else_ is not None:
- yield self.else_
+ yield self.else_
@property
def _from_objects(self):
@@ -3241,7 +3241,7 @@ class FunctionElement(Executable, ColumnElement, FromClause):
return self.clauses._from_objects
def get_children(self, **kwargs):
- return self.clause_expr,
+ return self.clause_expr,
def _copy_internals(self, clone=_clone, **kw):
self.clause_expr = clone(self.clause_expr, **kw)
@@ -3249,7 +3249,7 @@ class FunctionElement(Executable, ColumnElement, FromClause):
util.reset_memoized(self, 'clauses')
def select(self):
- """Produce a :func:`~.expression.select` construct
+ """Produce a :func:`~.expression.select` construct
against this :class:`.FunctionElement`.
This is shorthand for::
@@ -3266,10 +3266,10 @@ class FunctionElement(Executable, ColumnElement, FromClause):
"""Execute this :class:`.FunctionElement` against an embedded
'bind' and return a scalar value.
- This first calls :meth:`~.FunctionElement.select` to
+ This first calls :meth:`~.FunctionElement.select` to
produce a SELECT construct.
- Note that :class:`.FunctionElement` can be passed to
+ Note that :class:`.FunctionElement` can be passed to
the :meth:`.Connectable.scalar` method of :class:`.Connection`
or :class:`.Engine`.
@@ -3280,10 +3280,10 @@ class FunctionElement(Executable, ColumnElement, FromClause):
"""Execute this :class:`.FunctionElement` against an embedded
'bind'.
- This first calls :meth:`~.FunctionElement.select` to
+ This first calls :meth:`~.FunctionElement.select` to
produce a SELECT construct.
- Note that :class:`.FunctionElement` can be passed to
+ Note that :class:`.FunctionElement` can be passed to
the :meth:`.Connectable.execute` method of :class:`.Connection`
or :class:`.Engine`.
@@ -3291,7 +3291,7 @@ class FunctionElement(Executable, ColumnElement, FromClause):
return self.select().execute()
def _bind_param(self, operator, obj):
- return _BindParamClause(None, obj, _compared_to_operator=operator,
+ return _BindParamClause(None, obj, _compared_to_operator=operator,
_compared_to_type=self.type, unique=True)
@@ -3308,7 +3308,7 @@ class Function(FunctionElement):
def __init__(self, name, *clauses, **kw):
"""Construct a :class:`.Function`.
- The :attr:`.func` construct is normally used to construct
+ The :attr:`.func` construct is normally used to construct
new :class:`.Function` instances.
"""
@@ -3371,7 +3371,7 @@ class _UnaryExpression(ColumnElement):
__visit_name__ = 'unary'
- def __init__(self, element, operator=None, modifier=None,
+ def __init__(self, element, operator=None, modifier=None,
type_=None, negate=None):
self.operator = operator
self.modifier = modifier
@@ -3426,7 +3426,7 @@ class _BinaryExpression(ColumnElement):
__visit_name__ = 'binary'
- def __init__(self, left, right, operator, type_=None,
+ def __init__(self, left, right, operator, type_=None,
negate=None, modifiers=None):
self.left = _literal_as_text(left).self_group(against=operator)
self.right = _literal_as_text(right).self_group(against=operator)
@@ -3460,7 +3460,7 @@ class _BinaryExpression(ColumnElement):
return self.left, self.right
def compare(self, other, **kw):
- """Compare this :class:`_BinaryExpression` against the
+ """Compare this :class:`_BinaryExpression` against the
given :class:`_BinaryExpression`."""
return (
@@ -3626,10 +3626,10 @@ class Join(FromClause):
where(whereclause).\\
select_from(j)
- :param whereclause: the WHERE criterion that will be sent to
+ :param whereclause: the WHERE criterion that will be sent to
the :func:`select()` function
- :param fold_equivalents: based on the join criterion of this
+ :param fold_equivalents: based on the join criterion of this
:class:`.Join`, do not include
repeat column names in the column list of the resulting
select, for columns that are calculated to be "equivalent"
@@ -3637,7 +3637,7 @@ class Join(FromClause):
recursively apply to any joins directly nested by this one
as well.
- :param \**kwargs: all other kwargs are sent to the
+ :param \**kwargs: all other kwargs are sent to the
underlying :func:`select()` function.
"""
@@ -3657,9 +3657,9 @@ class Join(FromClause):
Used against a :class:`.Join` object,
:meth:`~.Join.alias` calls the :meth:`~.Join.select`
- method first so that a subquery against a
+ method first so that a subquery against a
:func:`.select` construct is generated.
- the :func:`~expression.select` construct also has the
+ the :func:`~expression.select` construct also has the
``correlate`` flag set to ``False`` and will not
auto-correlate inside an enclosing :func:`~expression.select`
construct.
@@ -3676,7 +3676,7 @@ class Join(FromClause):
name=name
)
- See :func:`~.expression.alias` for further details on
+ See :func:`~.expression.alias` for further details on
aliases.
"""
@@ -3788,12 +3788,15 @@ class CTE(Alias):
"""
__visit_name__ = 'cte'
- def __init__(self, selectable,
- name=None,
- recursive=False,
- cte_alias=False):
+
+ def __init__(self, selectable,
+ name=None,
+ recursive=False,
+ cte_alias=False,
+ _restates=frozenset()):
self.recursive = recursive
self.cte_alias = cte_alias
+ self._restates = _restates
super(CTE, self).__init__(selectable, name=name)
def alias(self, name=None):
@@ -3801,21 +3804,23 @@ class CTE(Alias):
self.original,
name=name,
recursive=self.recursive,
- cte_alias = self.name
+ cte_alias=self.name
)
def union(self, other):
return CTE(
self.original.union(other),
name=self.name,
- recursive=self.recursive
+ recursive=self.recursive,
+ _restates=self._restates.union([self])
)
def union_all(self, other):
return CTE(
self.original.union_all(other),
name=self.name,
- recursive=self.recursive
+ recursive=self.recursive,
+ _restates=self._restates.union([self])
)
@@ -3903,7 +3908,7 @@ class _FromGrouping(FromClause):
class _Over(ColumnElement):
"""Represent an OVER clause.
- This is a special operator against a so-called
+ This is a special operator against a so-called
"window" function, as well as any aggregate function,
which produces results relative to the result set
itself. It's supported only by certain database
@@ -3927,8 +3932,8 @@ class _Over(ColumnElement):
return self.func.type
def get_children(self, **kwargs):
- return [c for c in
- (self.func, self.partition_by, self.order_by)
+ return [c for c in
+ (self.func, self.partition_by, self.order_by)
if c is not None]
def _copy_internals(self, clone=_clone, **kw):
@@ -3941,8 +3946,8 @@ class _Over(ColumnElement):
@property
def _from_objects(self):
return list(itertools.chain(
- *[c._from_objects for c in
- (self.func, self.partition_by, self.order_by)
+ *[c._from_objects for c in
+ (self.func, self.partition_by, self.order_by)
if c is not None]
))
@@ -3987,8 +3992,8 @@ class _Label(ColumnElement):
def self_group(self, against=None):
sub_element = self._element.self_group(against=against)
if sub_element is not self._element:
- return _Label(self.name,
- sub_element,
+ return _Label(self.name,
+ sub_element,
type_=self._type)
else:
return self
@@ -4012,7 +4017,7 @@ class _Label(ColumnElement):
return self.element._from_objects
def _make_proxy(self, selectable, name=None, **kw):
- e = self.element._make_proxy(selectable,
+ e = self.element._make_proxy(selectable,
name=name if name else self.name)
e.proxies.append(self)
return e
@@ -4034,7 +4039,7 @@ class ColumnClause(_Immutable, ColumnElement):
s = select([c1, c2]).where(c1==5)
There is also a variant on :func:`~.expression.column` known
- as :func:`~.expression.literal_column` - the difference is that
+ as :func:`~.expression.literal_column` - the difference is that
in the latter case, the string value is assumed to be an exact
expression, rather than a column name, so that no quoting rules
or similar are applied::
@@ -4043,8 +4048,8 @@ class ColumnClause(_Immutable, ColumnElement):
s = select([literal_column("5 + 7")])
- :class:`.ColumnClause` can also be used in a table-like
- fashion by combining the :func:`~.expression.column` function
+ :class:`.ColumnClause` can also be used in a table-like
+ fashion by combining the :func:`~.expression.column` function
with the :func:`~.expression.table` function, to produce
a "lightweight" form of table metadata::
@@ -4064,10 +4069,10 @@ class ColumnClause(_Immutable, ColumnElement):
:param selectable: parent selectable.
- :param type: :class:`.types.TypeEngine` object which can associate
+ :param type: :class:`.types.TypeEngine` object which can associate
this :class:`.ColumnClause` with a type.
- :param is_literal: if True, the :class:`.ColumnClause` is assumed to
+ :param is_literal: if True, the :class:`.ColumnClause` is assumed to
be an exact expression that will be delivered to the output with no
quoting rules applied regardless of case sensitive settings. the
:func:`literal_column()` function is usually used to create such a
@@ -4078,7 +4083,7 @@ class ColumnClause(_Immutable, ColumnElement):
onupdate = default = server_default = server_onupdate = None
- _memoized_property = util.group_expirable_memoized_property()
+ _memoized_property = util.group_expirable_memoized_property()
def __init__(self, text, selectable=None, type_=None, is_literal=False):
self.key = self.name = text
@@ -4166,9 +4171,9 @@ class ColumnClause(_Immutable, ColumnElement):
# otherwise its considered to be a label
is_literal = self.is_literal and (name is None or name == self.name)
c = self._constructor(
- _as_truncated(name if name else self.name),
- selectable=selectable,
- type_=self.type,
+ _as_truncated(name if name else self.name),
+ selectable=selectable,
+ type_=self.type,
is_literal=is_literal
)
c.proxies = [self]
@@ -4184,8 +4189,8 @@ class TableClause(_Immutable, FromClause):
"""Represents a minimal "table" construct.
The constructor for :class:`.TableClause` is the
- :func:`~.expression.table` function. This produces
- a lightweight table object that has only a name and a
+ :func:`~.expression.table` function. This produces
+ a lightweight table object that has only a name and a
collection of columns, which are typically produced
by the :func:`~.expression.column` function::
@@ -4203,7 +4208,7 @@ class TableClause(_Immutable, FromClause):
the ``.c.`` collection and statement generation methods.
It does **not** provide all the additional schema-level services
- of :class:`~.schema.Table`, including constraints, references to other
+ of :class:`~.schema.Table`, including constraints, references to other
tables, or support for :class:`.MetaData`-level services. It's useful
on its own as an ad-hoc construct used to generate quick SQL
statements when a more fully fledged :class:`~.schema.Table` is not on hand.
@@ -4253,9 +4258,9 @@ class TableClause(_Immutable, FromClause):
else:
col = list(self.columns)[0]
return select(
- [func.count(col).label('tbl_row_count')],
- whereclause,
- from_obj=[self],
+ [func.count(col).label('tbl_row_count')],
+ whereclause,
+ from_obj=[self],
**params)
def insert(self, values=None, inline=False, **kwargs):
@@ -4284,7 +4289,7 @@ class TableClause(_Immutable, FromClause):
"""
- return update(self, whereclause=whereclause,
+ return update(self, whereclause=whereclause,
values=values, inline=inline, **kwargs)
def delete(self, whereclause=None, **kwargs):
@@ -4349,7 +4354,7 @@ class _SelectBase(Executable, FromClause):
Typically, a select statement which has only one column in its columns
clause is eligible to be used as a scalar expression.
- The returned object is an instance of
+ The returned object is an instance of
:class:`_ScalarSelect`.
"""
@@ -4383,8 +4388,8 @@ class _SelectBase(Executable, FromClause):
Common table expressions are a SQL standard whereby SELECT
statements can draw upon secondary statements specified along
with the primary statement, using a clause called "WITH".
- Special semantics regarding UNION can also be employed to
- allow "recursive" queries, where a SELECT statement can draw
+ Special semantics regarding UNION can also be employed to
+ allow "recursive" queries, where a SELECT statement can draw
upon the set of rows that have previously been selected.
SQLAlchemy detects :class:`.CTE` objects, which are treated
@@ -4399,11 +4404,11 @@ class _SelectBase(Executable, FromClause):
in which case an anonymous symbol will be used at query
compile time.
:param recursive: if ``True``, will render ``WITH RECURSIVE``.
- A recursive common table expression is intended to be used in
+ A recursive common table expression is intended to be used in
conjunction with UNION ALL in order to derive rows
from those already selected.
- The following examples illustrate two examples from
+ The following examples illustrate two examples from
Postgresql's documentation at
http://www.postgresql.org/docs/8.4/static/queries-with.html.
@@ -4422,23 +4427,23 @@ class _SelectBase(Executable, FromClause):
)
regional_sales = select([
- orders.c.region,
+ orders.c.region,
func.sum(orders.c.amount).label('total_sales')
]).group_by(orders.c.region).cte("regional_sales")
top_regions = select([regional_sales.c.region]).\\
where(
- regional_sales.c.total_sales >
+ regional_sales.c.total_sales >
select([
func.sum(regional_sales.c.total_sales)/10
])
).cte("top_regions")
statement = select([
- orders.c.region,
- orders.c.product,
- func.sum(orders.c.quantity).label("product_units"),
+ orders.c.region,
+ orders.c.product,
+ func.sum(orders.c.quantity).label("product_units"),
func.sum(orders.c.amount).label("product_sales")
]).where(orders.c.region.in_(
select([top_regions.c.region])
@@ -4460,8 +4465,8 @@ class _SelectBase(Executable, FromClause):
)
included_parts = select([
- parts.c.sub_part,
- parts.c.part,
+ parts.c.sub_part,
+ parts.c.part,
parts.c.quantity]).\\
where(parts.c.part=='our part').\\
cte(recursive=True)
@@ -4471,15 +4476,15 @@ class _SelectBase(Executable, FromClause):
parts_alias = parts.alias()
included_parts = included_parts.union_all(
select([
- parts_alias.c.part,
- parts_alias.c.sub_part,
+ parts_alias.c.part,
+ parts_alias.c.sub_part,
parts_alias.c.quantity
]).
where(parts_alias.c.part==incl_alias.c.sub_part)
)
statement = select([
- included_parts.c.sub_part,
+ included_parts.c.sub_part,
func.sum(included_parts.c.quantity).label('total_quantity')
]).\
select_from(included_parts.join(parts,
@@ -4608,7 +4613,7 @@ class _ScalarSelect(_Grouping):
selectable, name=name)
class CompoundSelect(_SelectBase):
- """Forms the basis of ``UNION``, ``UNION ALL``, and other
+ """Forms the basis of ``UNION``, ``UNION ALL``, and other
SELECT-based set operations."""
__visit_name__ = 'compound_select'
@@ -4669,7 +4674,7 @@ class CompoundSelect(_SelectBase):
# ForeignKeys in. this would allow the union() to have all
# those fks too.
- proxy = cols[0]._make_proxy(self,
+ proxy = cols[0]._make_proxy(self,
name=cols[0]._label if self.use_labels else None,
key=cols[0]._key_label if self.use_labels else None)
@@ -4730,14 +4735,14 @@ class Select(_SelectBase):
_correlate_except = ()
_memoized_property = _SelectBase._memoized_property
- def __init__(self,
- columns,
- whereclause=None,
- from_obj=None,
- distinct=False,
- having=None,
- correlate=True,
- prefixes=None,
+ def __init__(self,
+ columns,
+ whereclause=None,
+ from_obj=None,
+ distinct=False,
+ having=None,
+ correlate=True,
+ prefixes=None,
**kwargs):
"""Construct a Select object.
@@ -4765,13 +4770,13 @@ class Select(_SelectBase):
self._distinct = True
else:
self._distinct = [
- _literal_as_text(e)
+ _literal_as_text(e)
for e in util.to_list(distinct)
]
if from_obj is not None:
self._from_obj = util.OrderedSet(
- _literal_as_text(f)
+ _literal_as_text(f)
for f in util.to_list(from_obj))
else:
self._from_obj = util.OrderedSet()
@@ -4811,7 +4816,7 @@ class Select(_SelectBase):
def _froms(self):
# would love to cache this,
# but there's just enough edge cases, particularly now that
- # declarative encourages construction of SQL expressions
+ # declarative encourages construction of SQL expressions
# without tables present, to just regen this each time.
froms = []
seen = set()
@@ -4849,7 +4854,7 @@ class Select(_SelectBase):
# clones that are lexical equivalents.
if self._from_cloned:
toremove.update(
- self._from_cloned[f] for f in
+ self._from_cloned[f] for f in
toremove.intersection(self._from_cloned)
if self._from_cloned[f]._is_lexical_equivalent(f)
)
@@ -4862,7 +4867,7 @@ class Select(_SelectBase):
froms = [f for f in froms if f not in _cloned_intersection(froms,
self._correlate)]
if self._correlate_except:
- froms = [f for f in froms if f in _cloned_intersection(froms,
+ froms = [f for f in froms if f in _cloned_intersection(froms,
self._correlate_except)]
if self._should_correlate and existing_froms:
froms = [f for f in froms if f not in _cloned_intersection(froms,
@@ -5004,14 +5009,14 @@ class Select(_SelectBase):
return (column_collections and list(self.columns) or []) + \
self._raw_columns + list(self._froms) + \
- [x for x in
- (self._whereclause, self._having,
- self._order_by_clause, self._group_by_clause)
+ [x for x in
+ (self._whereclause, self._having,
+ self._order_by_clause, self._group_by_clause)
if x is not None]
@_generative
def column(self, column):
- """return a new select() construct with the given column expression
+ """return a new select() construct with the given column expression
added to its columns clause.
"""
@@ -5019,20 +5024,20 @@ class Select(_SelectBase):
@_generative
def with_only_columns(self, columns):
- """Return a new :func:`.select` construct with its columns
+ """Return a new :func:`.select` construct with its columns
clause replaced with the given columns.
.. versionchanged:: 0.7.3
- Due to a bug fix, this method has a slight
+ Due to a bug fix, this method has a slight
behavioral change as of version 0.7.3.
- Prior to version 0.7.3, the FROM clause of
+ Prior to version 0.7.3, the FROM clause of
a :func:`.select` was calculated upfront and as new columns
- were added; in 0.7.3 and later it's calculated
+ were added; in 0.7.3 and later it's calculated
at compile time, fixing an issue regarding late binding
- of columns to parent tables. This changes the behavior of
+ of columns to parent tables. This changes the behavior of
:meth:`.Select.with_only_columns` in that FROM clauses no
- longer represented in the new list are dropped,
- but this behavior is more consistent in
+ longer represented in the new list are dropped,
+ but this behavior is more consistent in
that the FROM clauses are consistently derived from the
current columns clause. The original intent of this method
is to allow trimming of the existing columns list to be fewer
@@ -5041,8 +5046,8 @@ class Select(_SelectBase):
been anticipated until 0.7.3 was released; the usage
guidelines below illustrate how this should be done.
- This method is exactly equivalent to as if the original
- :func:`.select` had been called with the given columns
+ This method is exactly equivalent to as if the original
+ :func:`.select` had been called with the given columns
clause. I.e. a statement::
s = select([table1.c.a, table1.c.b])
@@ -5052,8 +5057,8 @@ class Select(_SelectBase):
s = select([table1.c.b])
- This means that FROM clauses which are only derived
- from the column list will be discarded if the new column
+ This means that FROM clauses which are only derived
+ from the column list will be discarded if the new column
list no longer contains that FROM::
>>> table1 = table('t1', column('a'), column('b'))
@@ -5067,7 +5072,7 @@ class Select(_SelectBase):
The preferred way to maintain a specific FROM clause
in the construct, assuming it won't be represented anywhere
- else (i.e. not in the WHERE clause, etc.) is to set it using
+ else (i.e. not in the WHERE clause, etc.) is to set it using
:meth:`.Select.select_from`::
>>> s1 = select([table1.c.a, table2.c.b]).\\
@@ -5079,9 +5084,9 @@ class Select(_SelectBase):
Care should also be taken to use the correct
set of column objects passed to :meth:`.Select.with_only_columns`.
Since the method is essentially equivalent to calling the
- :func:`.select` construct in the first place with the given
- columns, the columns passed to :meth:`.Select.with_only_columns`
- should usually be a subset of those which were passed
+ :func:`.select` construct in the first place with the given
+ columns, the columns passed to :meth:`.Select.with_only_columns`
+ should usually be a subset of those which were passed
to the :func:`.select` construct, not those which are available
from the ``.c`` collection of that :func:`.select`. That
is::
@@ -5096,8 +5101,8 @@ class Select(_SelectBase):
The latter would produce the SQL::
- SELECT b
- FROM (SELECT t1.a AS a, t1.b AS b
+ SELECT b
+ FROM (SELECT t1.a AS a, t1.b AS b
FROM t1), t1
Since the :func:`.select` construct is essentially being
@@ -5152,14 +5157,14 @@ class Select(_SelectBase):
@_generative
def prefix_with(self, *expr):
"""return a new select() construct which will apply the given
- expressions, typically strings, to the start of its columns clause,
+ expressions, typically strings, to the start of its columns clause,
not using any commas. In particular is useful for MySQL
keywords.
e.g.::
- select(['a', 'b']).prefix_with('HIGH_PRIORITY',
- 'SQL_SMALL_RESULT',
+ select(['a', 'b']).prefix_with('HIGH_PRIORITY',
+ 'SQL_SMALL_RESULT',
'ALL')
Would render::
@@ -5187,14 +5192,14 @@ class Select(_SelectBase):
The "from" list is a unique set on the identity of each element,
so adding an already present :class:`.Table` or other selectable
will have no effect. Passing a :class:`.Join` that refers
- to an already present :class:`.Table` or other selectable will have
- the effect of concealing the presence of that selectable as
+ to an already present :class:`.Table` or other selectable will have
+ the effect of concealing the presence of that selectable as
an individual element in the rendered FROM list, instead rendering it into a
JOIN clause.
While the typical purpose of :meth:`.Select.select_from` is to replace
the default, derived FROM clause with a join, it can also be called with
- individual table elements, multiple times if desired, in the case that the
+ individual table elements, multiple times if desired, in the case that the
FROM clause cannot be fully derived from the columns clause::
select([func.count('*')]).select_from(table1)
@@ -5300,7 +5305,7 @@ class Select(_SelectBase):
def _populate_column_collection(self):
for c in self.inner_columns:
if hasattr(c, '_make_proxy'):
- c._make_proxy(self,
+ c._make_proxy(self,
name=c._label if self.use_labels else None,
key=c._key_label if self.use_labels else None)
@@ -5445,17 +5450,17 @@ class UpdateBase(Executable, ClauseElement):
column expression. :class:`~sqlalchemy.schema.Table` objects will be
expanded into their individual columns.
- Upon compilation, a RETURNING clause, or database equivalent,
- will be rendered within the statement. For INSERT and UPDATE,
- the values are the newly inserted/updated values. For DELETE,
+ Upon compilation, a RETURNING clause, or database equivalent,
+ will be rendered within the statement. For INSERT and UPDATE,
+ the values are the newly inserted/updated values. For DELETE,
the values are those of the rows which were deleted.
Upon execution, the values of the columns to be returned
are made available via the result set and can be iterated
using ``fetchone()`` and similar. For DBAPIs which do not
- natively support returning values (i.e. cx_oracle),
+ natively support returning values (i.e. cx_oracle),
SQLAlchemy will approximate this behavior at the result level
- so that a reasonable amount of behavioral neutrality is
+ so that a reasonable amount of behavioral neutrality is
provided.
Note that not all databases/DBAPIs
@@ -5463,8 +5468,8 @@ class UpdateBase(Executable, ClauseElement):
an exception is raised upon compilation and/or execution.
For those who do support it, the functionality across backends
varies greatly, including restrictions on executemany()
- and other statements which return multiple rows. Please
- read the documentation notes for the database in use in
+ and other statements which return multiple rows. Please
+ read the documentation notes for the database in use in
order to determine the availability of RETURNING.
"""
@@ -5472,20 +5477,20 @@ class UpdateBase(Executable, ClauseElement):
@_generative
def with_hint(self, text, selectable=None, dialect_name="*"):
- """Add a table hint for a single table to this
+ """Add a table hint for a single table to this
INSERT/UPDATE/DELETE statement.
.. note::
- :meth:`.UpdateBase.with_hint` currently applies only to
+ :meth:`.UpdateBase.with_hint` currently applies only to
Microsoft SQL Server. For MySQL INSERT hints, use
- :meth:`.Insert.prefix_with`. UPDATE/DELETE hints for
+ :meth:`.Insert.prefix_with`. UPDATE/DELETE hints for
MySQL will be added in a future release.
The text of the hint is rendered in the appropriate
location for the database backend in use, relative
to the :class:`.Table` that is the subject of this
- statement, or optionally to that of the given
+ statement, or optionally to that of the given
:class:`.Table` passed as the ``selectable`` argument.
The ``dialect_name`` option will limit the rendering of a particular
@@ -5523,7 +5528,7 @@ class ValuesBase(UpdateBase):
"""specify the VALUES clause for an INSERT statement, or the SET
clause for an UPDATE.
- :param \**kwargs: key value pairs representing the string key
+ :param \**kwargs: key value pairs representing the string key
of a :class:`.Column` mapped to the value to be rendered into the
VALUES or SET clause::
@@ -5541,7 +5546,7 @@ class ValuesBase(UpdateBase):
See also:
- :ref:`inserts_and_updates` - SQL Expression
+ :ref:`inserts_and_updates` - SQL Expression
Language Tutorial
:func:`~.expression.insert` - produce an ``INSERT`` statement
@@ -5576,12 +5581,12 @@ class Insert(ValuesBase):
_prefixes = ()
- def __init__(self,
- table,
- values=None,
- inline=False,
- bind=None,
- prefixes=None,
+ def __init__(self,
+ table,
+ values=None,
+ inline=False,
+ bind=None,
+ prefixes=None,
returning=None,
**kwargs):
ValuesBase.__init__(self, table, values)
@@ -5624,12 +5629,12 @@ class Update(ValuesBase):
"""
__visit_name__ = 'update'
- def __init__(self,
- table,
- whereclause,
- values=None,
- inline=False,
- bind=None,
+ def __init__(self,
+ table,
+ whereclause,
+ values=None,
+ inline=False,
+ bind=None,
returning=None,
**kwargs):
ValuesBase.__init__(self, table, values)
@@ -5691,10 +5696,10 @@ class Delete(UpdateBase):
__visit_name__ = 'delete'
- def __init__(self,
- table,
- whereclause,
- bind=None,
+ def __init__(self,
+ table,
+ whereclause,
+ bind=None,
returning =None,
**kwargs):
self._bind = bind
diff --git a/test/sql/test_cte.py b/test/sql/test_cte.py
index 36f992a86..59b347ccd 100644
--- a/test/sql/test_cte.py
+++ b/test/sql/test_cte.py
@@ -1,15 +1,16 @@
from test.lib import fixtures
-from test.lib.testing import AssertsCompiledSQL
+from test.lib.testing import AssertsCompiledSQL, assert_raises_message
from sqlalchemy.sql import table, column, select, func, literal
from sqlalchemy.dialects import mssql
from sqlalchemy.engine import default
+from sqlalchemy.exc import CompileError
class CTETest(fixtures.TestBase, AssertsCompiledSQL):
__dialect__ = 'default'
def test_nonrecursive(self):
- orders = table('orders',
+ orders = table('orders',
column('region'),
column('amount'),
column('product'),
@@ -17,22 +18,22 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
)
regional_sales = select([
- orders.c.region,
+ orders.c.region,
func.sum(orders.c.amount).label('total_sales')
]).group_by(orders.c.region).cte("regional_sales")
top_regions = select([regional_sales.c.region]).\
where(
- regional_sales.c.total_sales >
+ regional_sales.c.total_sales >
select([
func.sum(regional_sales.c.total_sales)/10
])
).cte("top_regions")
s = select([
- orders.c.region,
- orders.c.product,
- func.sum(orders.c.quantity).label("product_units"),
+ orders.c.region,
+ orders.c.product,
+ func.sum(orders.c.quantity).label("product_units"),
func.sum(orders.c.amount).label("product_sales")
]).where(orders.c.region.in_(
select([top_regions.c.region])
@@ -59,15 +60,15 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
)
def test_recursive(self):
- parts = table('parts',
+ parts = table('parts',
column('part'),
column('sub_part'),
column('quantity'),
)
included_parts = select([
- parts.c.sub_part,
- parts.c.part,
+ parts.c.sub_part,
+ parts.c.part,
parts.c.quantity]).\
where(parts.c.part=='our part').\
cte(recursive=True)
@@ -76,19 +77,19 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
parts_alias = parts.alias()
included_parts = included_parts.union(
select([
- parts_alias.c.part,
- parts_alias.c.sub_part,
+ parts_alias.c.part,
+ parts_alias.c.sub_part,
parts_alias.c.quantity]).\
where(parts_alias.c.part==incl_alias.c.sub_part)
)
s = select([
- included_parts.c.sub_part,
+ included_parts.c.sub_part,
func.sum(included_parts.c.quantity).label('total_quantity')]).\
select_from(included_parts.join(
parts,included_parts.c.part==parts.c.part)).\
group_by(included_parts.c.sub_part)
- self.assert_compile(s,
+ self.assert_compile(s,
"WITH RECURSIVE anon_1(sub_part, part, quantity) "
"AS (SELECT parts.sub_part AS sub_part, parts.part "
"AS part, parts.quantity AS quantity FROM parts "
@@ -104,7 +105,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
# quick check that the "WITH RECURSIVE" varies per
# dialect
- self.assert_compile(s,
+ self.assert_compile(s,
"WITH anon_1(sub_part, part, quantity) "
"AS (SELECT parts.sub_part AS sub_part, parts.part "
"AS part, parts.quantity AS quantity FROM parts "
@@ -119,8 +120,146 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
dialect=mssql.dialect()
)
+ def test_recursive_union_no_alias_one(self):
+ s1 = select([literal(0).label("x")])
+ cte = s1.cte(name="cte", recursive=True)
+ cte = cte.union_all(
+ select([cte.c.x + 1]).where(cte.c.x < 10)
+ )
+ s2 = select([cte])
+ self.assert_compile(s2,
+ "WITH RECURSIVE cte(x) AS "
+ "(SELECT :param_1 AS x UNION ALL "
+ "SELECT cte.x + :x_1 AS anon_1 "
+ "FROM cte WHERE cte.x < :x_2) "
+ "SELECT cte.x FROM cte"
+ )
+
+
+ def test_recursive_union_no_alias_two(self):
+ """
+
+ pg's example:
+
+ WITH RECURSIVE t(n) AS (
+ VALUES (1)
+ UNION ALL
+ SELECT n+1 FROM t WHERE n < 100
+ )
+ SELECT sum(n) FROM t;
+
+ """
+
+ # I know, this is the PG VALUES keyword,
+ # we're cheating here. also yes we need the SELECT,
+ # sorry PG.
+ t = select([func.values(1).label("n")]).cte("t", recursive=True)
+ t = t.union_all(select([t.c.n + 1]).where(t.c.n < 100))
+ s = select([func.sum(t.c.n)])
+ self.assert_compile(s,
+ "WITH RECURSIVE t(n) AS "
+ "(SELECT values(:values_1) AS n "
+ "UNION ALL SELECT t.n + :n_1 AS anon_1 "
+ "FROM t "
+ "WHERE t.n < :n_2) "
+ "SELECT sum(t.n) AS sum_1 FROM t"
+ )
+
+ def test_recursive_union_no_alias_three(self):
+ # like test one, but let's refer to the CTE
+ # in a sibling CTE.
+
+ s1 = select([literal(0).label("x")])
+ cte = s1.cte(name="cte", recursive=True)
+
+ # can't do it here...
+ #bar = select([cte]).cte('bar')
+ cte = cte.union_all(
+ select([cte.c.x + 1]).where(cte.c.x < 10)
+ )
+ bar = select([cte]).cte('bar')
+
+ s2 = select([cte, bar])
+ self.assert_compile(s2,
+ "WITH RECURSIVE cte(x) AS "
+ "(SELECT :param_1 AS x UNION ALL "
+ "SELECT cte.x + :x_1 AS anon_1 "
+ "FROM cte WHERE cte.x < :x_2), "
+ "bar AS (SELECT cte.x AS x FROM cte) "
+ "SELECT cte.x, bar.x FROM cte, bar"
+ )
+
+
+ def test_recursive_union_no_alias_four(self):
+ # like test one and three, but let's refer
+ # previous version of "cte". here we test
+ # how the compiler resolves multiple instances
+ # of "cte".
+
+ s1 = select([literal(0).label("x")])
+ cte = s1.cte(name="cte", recursive=True)
+
+ bar = select([cte]).cte('bar')
+ cte = cte.union_all(
+ select([cte.c.x + 1]).where(cte.c.x < 10)
+ )
+
+ # outer cte rendered first, then bar, which
+ # includes "inner" cte
+ s2 = select([cte, bar])
+ self.assert_compile(s2,
+ "WITH RECURSIVE cte(x) AS "
+ "(SELECT :param_1 AS x UNION ALL "
+ "SELECT cte.x + :x_1 AS anon_1 "
+ "FROM cte WHERE cte.x < :x_2), "
+ "bar AS (SELECT cte.x AS x FROM cte) "
+ "SELECT cte.x, bar.x FROM cte, bar"
+ )
+
+ # bar rendered, only includes "inner" cte,
+ # "outer" cte isn't present
+ s2 = select([bar])
+ self.assert_compile(s2,
+ "WITH RECURSIVE cte(x) AS "
+ "(SELECT :param_1 AS x), "
+ "bar AS (SELECT cte.x AS x FROM cte) "
+ "SELECT bar.x FROM bar"
+ )
+
+ # bar rendered, but then the "outer"
+ # cte is rendered.
+ s2 = select([bar, cte])
+ self.assert_compile(s2,
+ "WITH RECURSIVE bar AS (SELECT cte.x AS x FROM cte), "
+ "cte(x) AS "
+ "(SELECT :param_1 AS x UNION ALL "
+ "SELECT cte.x + :x_1 AS anon_1 "
+ "FROM cte WHERE cte.x < :x_2) "
+
+ "SELECT bar.x, cte.x FROM bar, cte"
+ )
+
+ def test_conflicting_names(self):
+ """test a flat out name conflict."""
+
+ s1 = select([1])
+ c1= s1.cte(name='cte1', recursive=True)
+ s2 = select([1])
+ c2 = s2.cte(name='cte1', recursive=True)
+
+ s = select([c1, c2])
+ assert_raises_message(
+ CompileError,
+ "Multiple, unrelated CTEs found "
+ "with the same name: 'cte1'",
+ s.compile
+ )
+
+
+
+
def test_union(self):
- orders = table('orders',
+ orders = table('orders',
column('region'),
column('amount'),
)
@@ -135,7 +274,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
regional_sales.c.amount > 500
)
- self.assert_compile(s,
+ self.assert_compile(s,
"WITH regional_sales AS "
"(SELECT orders.region AS region, "
"orders.amount AS amount FROM orders) "
@@ -149,7 +288,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
regional_sales.c.amount < 300
)
)
- self.assert_compile(s,
+ self.assert_compile(s,
"WITH regional_sales AS "
"(SELECT orders.region AS region, "
"orders.amount AS amount FROM orders) "
@@ -160,7 +299,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
"regional_sales.amount < :amount_2")
def test_reserved_quote(self):
- orders = table('orders',
+ orders = table('orders',
column('order'),
)
s = select([orders.c.order]).cte("regional_sales", recursive=True)
@@ -174,7 +313,7 @@ class CTETest(fixtures.TestBase, AssertsCompiledSQL):
)
def test_positional_binds(self):
- orders = table('orders',
+ orders = table('orders',
column('order'),
)
s = select([orders.c.order, literal("x")]).cte("regional_sales")