From: Mike Bayer Date: Fri, 4 Nov 2005 00:37:26 +0000 (+0000) Subject: (no commit message) X-Git-Tag: rel_0_1_0~392 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4daa406463c07ff3a6d8b636d8820714e865399;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git --- diff --git a/lib/sqlalchemy/ansisql.py b/lib/sqlalchemy/ansisql.py index f5ec9c11d7..31b401595b 100644 --- a/lib/sqlalchemy/ansisql.py +++ b/lib/sqlalchemy/ansisql.py @@ -118,7 +118,7 @@ class ANSICompiler(sql.Compiled): self.strings[compound] = "(" + string.join([self.get_str(c) for c in compound.clauses], sep) + ")" else: self.strings[compound] = string.join([self.get_str(c) for c in compound.clauses], sep) - + def visit_clauselist(self, list): self.strings[list] = string.join([self.get_str(c) for c in list.clauses], ', ') @@ -172,7 +172,7 @@ class ANSICompiler(sql.Compiled): whereclause = select.whereclause froms = [] - for f in select.froms.values(): + for f in select.froms: # special thingy used by oracle to redefine a join w = self.get_whereclause(f) diff --git a/lib/sqlalchemy/mapper.py b/lib/sqlalchemy/mapper.py index 5c082a95fd..756ea49046 100644 --- a/lib/sqlalchemy/mapper.py +++ b/lib/sqlalchemy/mapper.py @@ -966,7 +966,7 @@ class LazyLoader(PropertyLoader): if self.secondary is not None: order_by = [self.secondary.rowid_column] else: - order_by = [self.target.rowid_column] + order_by = [] result = self.mapper.select(self.lazywhere, order_by=order_by,**params) if self.uselist: return result diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index bae42022e8..1d3f74e1ab 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -23,7 +23,7 @@ import sqlalchemy.util as util import sqlalchemy.types as types import string -__ALL__ = ['textclause', 'select', 'join', 'and_', 'or_', 'union', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'bindparam', 'sequence'] +__ALL__ = ['textclause', 'select', 'join', 'and_', 'or_', 'union', 'unionall', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'bindparam', 'sequence'] def desc(column): """returns a descending ORDER BY clause element, e.g.: @@ -125,6 +125,9 @@ def exists(*args, **params): def union(*selects, **params): return _compound_select('UNION', *selects, **params) +def union_all(*selects, **params): + return _compound_select('UNION ALL', *selects, **params) + def alias(*args, **params): return Alias(*args, **params) @@ -178,6 +181,7 @@ class ClauseVisitor(schema.SchemaVisitor): def visit_select(self, select):pass def visit_join(self, join):pass def visit_null(self, null):pass + def visit_clauselist(self, list):pass class Compiled(ClauseVisitor): """represents a compiled SQL expression. the __str__ method of the Compiled object @@ -523,6 +527,9 @@ class Selectable(FromClause): def outerjoin(self, right, *args, **kwargs): return Join(self, right, isouter = True, *args, **kwargs) + def alias(self, name): + return Alias(self, name) + def group_parenthesized(self): """indicates if this Selectable requires parenthesis when grouped into a compound statement""" return True @@ -679,6 +686,9 @@ class TableImpl(Selectable): def outerjoin(self, right, *args, **kwargs): return Join(self.table, right, isouter = True, *args, **kwargs) + + def alias(self, name): + return Alias(self.table, name) def select(self, whereclauses = None, **params): return select([self.table], whereclauses, **params) @@ -709,7 +719,7 @@ class Select(Selectable): the ability to execute itself and return a result set.""" def __init__(self, columns, whereclause = None, from_obj = [], group_by = None, order_by = None, use_labels = False, engine = None): self.columns = util.OrderedProperties() - self.froms = util.OrderedDict() + self._froms = util.OrderedDict() self.use_labels = use_labels self.id = "Select(%d)" % id(self) self.name = None @@ -724,6 +734,7 @@ class Select(Selectable): self._text = None self._raw_columns = [] self._clauses = [] + self._correlated = None for c in columns: self.append_column(c) @@ -740,17 +751,26 @@ class Select(Selectable): if order_by: self.order_by(*order_by) + class CorrelatedVisitor(ClauseVisitor): + def __init__(self, select): + self.select = select + def visit_select(self, select): + if select is self.select: + return + select.issubquery = True + select._correlated = self.select._froms + def append_column(self, column): if _is_literal(column): column = ColumnClause(str(column), self) self._raw_columns.append(column) - column._process_from_dict(self.froms, False) + column._process_from_dict(self._froms, False) for f in column._get_from_objects(): if self.rowid_column is None and hasattr(f, 'rowid_column'): self.rowid_column = f.rowid_column._make_proxy(self) - + for co in column.columns: if self.use_labels: co._make_proxy(self, name = co.label) @@ -761,14 +781,9 @@ class Select(Selectable): if type(whereclause) == str: whereclause = TextClause(whereclause) - class CorrelatedVisitor(ClauseVisitor): - def visit_select(s, select): - for f in self.froms.keys(): - select.clear_from(f) - select.issubquery = True - - whereclause.accept_visitor(CorrelatedVisitor()) - whereclause._process_from_dict(self.froms, False) + visitor = Select.CorrelatedVisitor(self) + whereclause.accept_visitor(visitor) + whereclause._process_from_dict(self._froms, False) if self.whereclause is not None: self.whereclause = and_(self.whereclause, whereclause) @@ -782,7 +797,7 @@ class Select(Selectable): if type(fromclause) == str: fromclause = FromClause(from_name = fromclause) - fromclause._process_from_dict(self.froms, True) + fromclause._process_from_dict(self._froms, True) def append_clause(self, keyword, clause): if type(clause) == str: @@ -796,10 +811,18 @@ class Select(Selectable): if engine is None: raise "no engine supplied, and no engine could be located within the clauses!" + # TODO: this has issues + #visitor = Select.CorrelatedVisitor(self) + #self.accept_visitor(visitor) + return engine.compile(self, bindparams) + def _get_froms(self): + return [f for f in self._froms.values() if self._correlated is None or not self._correlated.has_key(f.id)] + froms = property(lambda s: s._get_froms()) + def accept_visitor(self, visitor): - for f in self.froms.values(): + for f in self.froms: f.accept_visitor(visitor) if self.whereclause is not None: self.whereclause.accept_visitor(visitor) @@ -825,7 +848,7 @@ class Select(Selectable): if self._engine: return self._engine - for f in self.froms.values(): + for f in self.froms: e = f.engine if e is not None: return e diff --git a/test/select.py b/test/select.py index 3c626eaf9d..86b9861d65 100644 --- a/test/select.py +++ b/test/select.py @@ -156,7 +156,7 @@ sq.myothertable_othername AS sq_myothertable_othername FROM (" + sqstring + ") s # create a select for a join of two tables. use_labels means the column names will have # labels tablename_columnname, which become the column keys accessible off the Selectable object. # also, only use one column from the second table and all columns from the first table. - q = select([table, table2.c.id], table.c.id == table2.c.id, use_labels = False) + q = select([table, table2.c.id], table.c.id == table2.c.id, use_labels = True) # make an alias of the "selectable". column names stay the same (i.e. the labels), table name "changes" to "t2view". a = alias(q, 't2view')