Example #1
0
def find_tables(clause, check_columns=False, include_aliases=False, include_joins=False, include_selects=False):
    """locate Table objects within the given expression."""

    tables = []
    _visitors = {}

    def visit_something(elem):
        tables.append(elem)

    if include_selects:
        _visitors["select"] = _visitors["compound_select"] = visit_something

    if include_joins:
        _visitors["join"] = visit_something

    if include_aliases:
        _visitors["alias"] = visit_something

    if check_columns:

        def visit_column(column):
            tables.append(column.table)

        _visitors["column"] = visit_column

    _visitors["table"] = visit_something

    visitors.traverse(clause, {"column_collections": False}, _visitors)
    return tables
Example #2
0
def folded_equivalents(join, equivs=None):
    """Returns the column list of the given Join with all equivalently-named,
    equated columns folded into one column, where 'equated' means they are
    equated to each other in the ON clause of this join.

    This function is used by Join.select(fold_equivalents=True).
    
    TODO: deprecate ?
    """

    if equivs is None:
        equivs = util.Set()
    def visit_binary(binary):
        if binary.operator == operators.eq and binary.left.name == binary.right.name:
            equivs.add(binary.right)
            equivs.add(binary.left)
    visitors.traverse(join.onclause, visit_binary=visit_binary)
    collist = []
    if isinstance(join.left, expression.Join):
        left = folded_equivalents(join.left, equivs)
    else:
        left = list(join.left.columns)
    if isinstance(join.right, expression.Join):
        right = folded_equivalents(join.right, equivs)
    else:
        right = list(join.right.columns)
    used = util.Set()
    for c in left + right:
        if c in equivs:
            if c.name not in used:
                collist.append(c)
                used.add(c.name)
        else:
            collist.append(c)
    return collist
def _params_from_query(query):
    """Pull the bind parameter values from a query.

    This takes into account any scalar attribute bindparam set up.

    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
    would return [5, 7].

    """
    v = []
    def visit_bindparam(bind):

        if bind.key in query._params:
            value = query._params[bind.key]
        elif bind.callable:
            # lazyloader may dig a callable in here, intended
            # to late-evaluate params after autoflush is called.
            # convert to a scalar value.
            value = bind.callable()
        else:
            value = bind.value

        v.append(value)
    if query._criterion is not None:
        visitors.traverse(query._criterion, {}, {'bindparam':visit_bindparam})
    for f in query._from_obj:
        visitors.traverse(f, {}, {'bindparam':visit_bindparam})
    return v
Example #4
0
def find_tables(clause,
                check_columns=False,
                include_aliases=False,
                include_joins=False,
                include_selects=False):
    """locate Table objects within the given expression."""

    tables = []
    _visitors = {}

    if include_selects:
        _visitors['select'] = _visitors['compound_select'] = tables.append

    if include_joins:
        _visitors['join'] = tables.append

    if include_aliases:
        _visitors['alias'] = tables.append

    if check_columns:

        def visit_column(column):
            tables.append(column.table)

        _visitors['column'] = visit_column

    _visitors['table'] = tables.append

    visitors.traverse(clause, {'column_collections': False}, _visitors)
    return tables
Example #5
0
    def select(self, *clauses):
        """Run a select query
        
        Arguments
        *clauses -- SQLAlchemy index clauses

        Returns:
        [records matching clauses]
        """
        if not clauses:
            return []

        clauses = reduce(sqlalchemy.and_, clauses) if clauses else []

        tables = []
        def check_unique_table(column):
            if tables and column.table not in tables:
                raise NotImplementedError("Can't join indices yet")
            tables.append(column.table)
        visitors.traverse(clauses, {}, {'column': functools.partial(check_unique_table)})
        assert tables

        index_vals = []
        for index in self.indices:
            if index.table == tables[0]:
                index_vals.extend(index.select(clauses))
                break
        ids = set(i.id for i in index_vals)
        return self.lookup(ids)
Example #6
0
def _params_from_query(query):
    """Pull the bind parameter values from a query.

    This takes into account any scalar attribute bindparam set up.

    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
    would return [5, 7].

    """
    v = []

    def visit_bindparam(bind):

        if bind.key in query._params:
            value = query._params[bind.key]
        elif bind.callable:
            # lazyloader may dig a callable in here, intended
            # to late-evaluate params after autoflush is called.
            # convert to a scalar value.
            value = bind.callable()
        else:
            value = bind.value

        v.append(value)

    if query._criterion is not None:
        visitors.traverse(query._criterion, {}, {'bindparam': visit_bindparam})
    for f in query._from_obj:
        visitors.traverse(f, {}, {'bindparam': visit_bindparam})
    return v
Example #7
0
def _params_from_query(query):
    """Pull the bind parameter values from a query.

    This takes into account any scalar attribute bindparam set up.

    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
    would return [5, 7].

    """
    vals = []

    def visit_bindparam(bind):
        value = query._params.get(bind.key, bind.value)

        # lazyloader may dig a callable in here, intended
        # to late-evaluate params after autoflush is called.
        # convert to a scalar value.
        if callable(value):
            value = value()

        vals.append(value)

    if query._criterion is not None:
        visitors.traverse(query._criterion, {}, {"bindparam": visit_bindparam})
    return vals
Example #8
0
def _key_from_query(query, qualifier=None):
    """Given a Query, create a cache key.

    There are many approaches to this; here we use the simplest,
    which is to create an md5 hash of the text of the SQL statement,
    combined with stringified versions of all the bound parameters
    within it.     There's a bit of a performance hit with
    compiling out "query.statement" here; other approaches include
    setting up an explicit cache key with a particular Query,
    then combining that with the bound parameter values.

    """

    v = []

    def visit_bindparam(bind):

        if bind.key in query._params:
            value = query._params[bind.key]
        elif bind.callable:
            value = bind.callable()
        else:
            value = bind.value

        v.append(unicode(value))

    stmt = query.statement
    visitors.traverse(stmt, {}, {'bindparam': visit_bindparam})

    # here we return the key as a long string.  our "key mangler"
    # set up with the region will boil it down to an md5.
    return " ".join([unicode(stmt)] + v)
Example #9
0
def find_tables(clause, check_columns=False, include_aliases=False):
    tables = []
    kwargs = {}
    if include_aliases:

        def visit_alias(alias):
            tables.append(alias)

        kwargs['visit_alias'] = visit_alias

    if check_columns:

        def visit_column(column):
            tables.append(column.table)

        kwargs['visit_column'] = visit_column

    def visit_table(table):
        tables.append(table)

    kwargs['visit_table'] = visit_table

    visitors.traverse(clause,
                      traverse_options={'column_collections': False},
                      **kwargs)
    return tables
Example #10
0
def criterion_as_pairs(expression, consider_as_foreign_keys=None, consider_as_referenced_keys=None, any_operator=False):
    """traverse an expression and locate binary criterion pairs."""

    if consider_as_foreign_keys and consider_as_referenced_keys:
        raise exc.ArgumentError("Can only specify one of 'consider_as_foreign_keys' or 'consider_as_referenced_keys'")

    def visit_binary(binary):
        if not any_operator and binary.operator is not operators.eq:
            return
        if not isinstance(binary.left, sql.ColumnElement) or not isinstance(binary.right, sql.ColumnElement):
            return

        if consider_as_foreign_keys:
            if binary.left in consider_as_foreign_keys:
                pairs.append((binary.right, binary.left))
            elif binary.right in consider_as_foreign_keys:
                pairs.append((binary.left, binary.right))
        elif consider_as_referenced_keys:
            if binary.left in consider_as_referenced_keys:
                pairs.append((binary.left, binary.right))
            elif binary.right in consider_as_referenced_keys:
                pairs.append((binary.right, binary.left))
        else:
            if isinstance(binary.left, schema.Column) and isinstance(binary.right, schema.Column):
                if binary.left.references(binary.right):
                    pairs.append((binary.right, binary.left))
                elif binary.right.references(binary.left):
                    pairs.append((binary.left, binary.right))

    pairs = []
    visitors.traverse(expression, {}, {"binary": visit_binary})
    return pairs
Example #11
0
def bind_values(clause):
    """Return an ordered list of "bound" values in the given clause.

    E.g.::

        >>> expr = and_(
        ...    table.c.foo==5, table.c.foo==7
        ... )
        >>> bind_values(expr)
        [5, 7]
    """

    v = []

    def visit_bindparam(bind):
        value = bind.value

        # evaluate callables
        if callable(value):
            value = value()

        v.append(value)

    visitors.traverse(clause, {}, {"bindparam": visit_bindparam})
    return v
Example #12
0
def sort_tables(tables, extra_dependencies=None):
    """sort a collection of Table objects in order of their foreign-key dependency."""

    tables = list(tables)
    tuples = []
    if extra_dependencies:
        tuples.extend(extra_dependencies)

    def visit_foreign_key(fkey):
        if fkey.use_alter:
            return
        parent_table = fkey.column.table
        if parent_table in tables:
            child_table = fkey.parent.table
            if parent_table is not child_table:
                tuples.append((parent_table, child_table))

    for table in tables:
        visitors.traverse(table,
                            {'schema_visitor': True},
                            {'foreign_key': visit_foreign_key})

        tuples.extend(
            [parent, table] for parent in table._extra_dependencies
        )

    return list(topological.sort(tuples, tables))
Example #13
0
File: util.py Project: Kellel/items
def find_tables(clause, check_columns=False, 
                include_aliases=False, include_joins=False, 
                include_selects=False, include_crud=False):
    """locate Table objects within the given expression."""

    tables = []
    _visitors = {}

    if include_selects:
        _visitors['select'] = _visitors['compound_select'] = tables.append

    if include_joins:
        _visitors['join'] = tables.append

    if include_aliases:
        _visitors['alias']  = tables.append

    if include_crud:
        _visitors['insert'] = _visitors['update'] = \
                    _visitors['delete'] = lambda ent: tables.append(ent.table)

    if check_columns:
        def visit_column(column):
            tables.append(column.table)
        _visitors['column'] = visit_column

    _visitors['table'] = tables.append

    visitors.traverse(clause, {'column_collections':False}, _visitors)
    return tables
Example #14
0
def _key_from_query(query, qualifier=None):
    """Given a Query, create a cache key.

    There are many approaches to this; here we use the simplest,
    which is to create an md5 hash of the text of the SQL statement,
    combined with stringified versions of all the bound parameters
    within it.     There's a bit of a performance hit with
    compiling out "query.statement" here; other approaches include
    setting up an explicit cache key with a particular Query,
    then combining that with the bound parameter values.

    """

    v = []
    def visit_bindparam(bind):

        if bind.key in query._params:
            value = query._params[bind.key]
        elif bind.callable:
            value = bind.callable()
        else:
            value = bind.value

        v.append(unicode(value))

    stmt = query.statement
    visitors.traverse(stmt, {}, {'bindparam': visit_bindparam})

    # here we return the key as a long string.  our "key mangler"
    # set up with the region will boil it down to an md5.
    return " ".join([unicode(stmt)] + v)
def _params_from_query(query):
    """Pull the bind parameter values from a query.

    This takes into account any scalar attribute bindparam set up.

    E.g. params_from_query(query.filter(Cls.foo==5).filter(Cls.bar==7)))
    would return [5, 7].

    """
    v = []
    def visit_bindparam(bind):

        if bind.key in query._params:
            value = query._params[bind.key]
        elif bind.callable:
            # lazyloader may dig a callable in here, intended
            # to late-evaluate params after autoflush is called.
            # convert to a scalar value.
            value = bind.callable()
        else:
            value = bind.value

        v.append(value)

    # TODO: this pulls the binds from the final compiled statement.
    # ideally, this would be a little more performant if it pulled
    # from query._criterion and others directly, however this would
    # need to be implemented not to miss anything, including
    # subqueries in the columns clause.  See
    # http://stackoverflow.com/questions/9265900/sqlalchemy-how-to-traverse-bindparam-values-in-a-subquery/
    visitors.traverse(query.statement, {}, {'bindparam':visit_bindparam})
    return v
Example #16
0
def bind_values(clause):
    """Return an ordered list of "bound" values in the given clause.

    E.g.::

        >>> expr = and_(
        ...    table.c.foo==5, table.c.foo==7
        ... )
        >>> bind_values(expr)
        [5, 7]
    """

    v = []

    def visit_bindparam(bind):
        value = bind.value

        # evaluate callables
        if callable(value):
            value = value()

        v.append(value)

    visitors.traverse(clause, {}, {'bindparam': visit_bindparam})
    return v
Example #17
0
def find_tables(
    clause, check_columns=False, include_aliases=False, include_joins=False, include_selects=False, include_crud=False
):
    """locate Table objects within the given expression."""

    tables = []
    _visitors = {}

    if include_selects:
        _visitors["select"] = _visitors["compound_select"] = tables.append

    if include_joins:
        _visitors["join"] = tables.append

    if include_aliases:
        _visitors["alias"] = tables.append

    if include_crud:
        _visitors["insert"] = _visitors["update"] = _visitors["delete"] = lambda ent: tables.append(ent.table)

    if check_columns:

        def visit_column(column):
            tables.append(column.table)

        _visitors["column"] = visit_column

    _visitors["table"] = tables.append

    visitors.traverse(clause, {"column_collections": False}, _visitors)
    return tables
Example #18
0
def criterion_as_pairs(expression, consider_as_foreign_keys=None, consider_as_referenced_keys=None, any_operator=False):
    """traverse an expression and locate binary criterion pairs."""

    if consider_as_foreign_keys and consider_as_referenced_keys:
        raise exc.ArgumentError("Can only specify one of 'consider_as_foreign_keys' or 'consider_as_referenced_keys'")

    def visit_binary(binary):
        if not any_operator and binary.operator is not operators.eq:
            return
        if not isinstance(binary.left, sql.ColumnElement) or not isinstance(binary.right, sql.ColumnElement):
            return

        if consider_as_foreign_keys:
            if binary.left in consider_as_foreign_keys and (binary.right is binary.left or binary.right not in consider_as_foreign_keys):
                pairs.append((binary.right, binary.left))
            elif binary.right in consider_as_foreign_keys and (binary.left is binary.right or binary.left not in consider_as_foreign_keys):
                pairs.append((binary.left, binary.right))
        elif consider_as_referenced_keys:
            if binary.left in consider_as_referenced_keys and (binary.right is binary.left or binary.right not in consider_as_referenced_keys):
                pairs.append((binary.left, binary.right))
            elif binary.right in consider_as_referenced_keys and (binary.left is binary.right or binary.left not in consider_as_referenced_keys):
                pairs.append((binary.right, binary.left))
        else:
            if isinstance(binary.left, schema.Column) and isinstance(binary.right, schema.Column):
                if binary.left.references(binary.right):
                    pairs.append((binary.right, binary.left))
                elif binary.right.references(binary.left):
                    pairs.append((binary.left, binary.right))
    pairs = []
    visitors.traverse(expression, {}, {'binary':visit_binary})
    return pairs
Example #19
0
def find_columns(clause):
    """locate Column objects within the given expression."""

    cols = util.column_set()
    def visit_column(col):
        cols.add(col)
    visitors.traverse(clause, {}, {'column':visit_column})
    return cols
Example #20
0
def find_columns(clause):
    cols = util.Set()

    def visit_column(col):
        cols.add(col)

    visitors.traverse(clause, visit_column=visit_column)
    return cols
Example #21
0
    def _create_lazy_clause(cls, prop, reverse_direction=False):
        (primaryjoin, secondaryjoin,
         remote_side) = (prop.polymorphic_primaryjoin,
                         prop.polymorphic_secondaryjoin, prop.remote_side)

        binds = {}
        equated_columns = {}

        def should_bind(targetcol, othercol):
            if not prop._col_is_part_of_mappings(targetcol):
                return False

            if reverse_direction and not secondaryjoin:
                return targetcol in remote_side
            else:
                return othercol in remote_side

        def visit_binary(binary):
            if not isinstance(binary.left,
                              sql.ColumnElement) or not isinstance(
                                  binary.right, sql.ColumnElement):
                return
            leftcol = binary.left
            rightcol = binary.right

            equated_columns[rightcol] = leftcol
            equated_columns[leftcol] = rightcol

            if should_bind(leftcol, rightcol):
                if leftcol in binds:
                    binary.left = binds[leftcol]
                else:
                    binary.left = binds[leftcol] = sql.bindparam(
                        None, None, type_=binary.right.type)

            # the "left is not right" compare is to handle part of a join clause that is "table.c.col1==table.c.col1",
            # which can happen in rare cases (test/orm/relationships.py RelationTest2)
            if leftcol is not rightcol and should_bind(rightcol, leftcol):
                if rightcol in binds:
                    binary.right = binds[rightcol]
                else:
                    binary.right = binds[rightcol] = sql.bindparam(
                        None, None, type_=binary.left.type)

        lazywhere = primaryjoin

        if not secondaryjoin or not reverse_direction:
            lazywhere = visitors.traverse(lazywhere,
                                          clone=True,
                                          visit_binary=visit_binary)

        if secondaryjoin is not None:
            if reverse_direction:
                secondaryjoin = visitors.traverse(secondaryjoin,
                                                  clone=True,
                                                  visit_binary=visit_binary)
            lazywhere = sql.and_(lazywhere, secondaryjoin)
        return (lazywhere, binds, equated_columns)
Example #22
0
def reduce_columns(columns, *clauses, **kw):
    """given a list of columns, return a 'reduced' set based on natural equivalents.

    the set is reduced to the smallest list of columns which have no natural
    equivalent present in the list.  A "natural equivalent" means that two columns
    will ultimately represent the same value because they are related by a foreign key.

    \*clauses is an optional list of join clauses which will be traversed
    to further identify columns that are "equivalent".

    \**kw may specify 'ignore_nonexistent_tables' to ignore foreign keys
    whose tables are not yet configured.
    
    This function is primarily used to determine the most minimal "primary key"
    from a selectable, by reducing the set of primary key columns present
    in the the selectable to just those that are not repeated.

    """
    ignore_nonexistent_tables = kw.pop('ignore_nonexistent_tables', False)

    columns = util.ordered_column_set(columns)

    omit = util.column_set()
    for col in columns:
        for fk in chain(*[c.foreign_keys for c in col.proxy_set]):
            for c in columns:
                if c is col:
                    continue
                try:
                    fk_col = fk.column
                except exc.NoReferencedTableError:
                    if ignore_nonexistent_tables:
                        continue
                    else:
                        raise
                if fk_col.shares_lineage(c):
                    omit.add(col)
                    break

    if clauses:

        def visit_binary(binary):
            if binary.operator == operators.eq:
                cols = util.column_set(
                    chain(*[c.proxy_set for c in columns.difference(omit)]))
                if binary.left in cols and binary.right in cols:
                    for c in columns:
                        if c.shares_lineage(binary.right):
                            omit.add(c)
                            break

        for clause in clauses:
            visitors.traverse(clause, {}, {'binary': visit_binary})

    return expression.ColumnSet(columns.difference(omit))
Example #23
0
def reduce_columns(columns, *clauses, **kw):
    """given a list of columns, return a 'reduced' set based on natural equivalents.

    the set is reduced to the smallest list of columns which have no natural
    equivalent present in the list.  A "natural equivalent" means that two columns
    will ultimately represent the same value because they are related by a foreign key.

    \*clauses is an optional list of join clauses which will be traversed
    to further identify columns that are "equivalent".

    \**kw may specify 'ignore_nonexistent_tables' to ignore foreign keys
    whose tables are not yet configured.

    This function is primarily used to determine the most minimal "primary key"
    from a selectable, by reducing the set of primary key columns present
    in the the selectable to just those that are not repeated.

    """
    ignore_nonexistent_tables = kw.pop("ignore_nonexistent_tables", False)

    columns = util.ordered_column_set(columns)

    omit = util.column_set()
    for col in columns:
        for fk in chain(*[c.foreign_keys for c in col.proxy_set]):
            for c in columns:
                if c is col:
                    continue
                try:
                    fk_col = fk.column
                except exc.NoReferencedTableError:
                    if ignore_nonexistent_tables:
                        continue
                    else:
                        raise
                if fk_col.shares_lineage(c):
                    omit.add(col)
                    break

    if clauses:

        def visit_binary(binary):
            if binary.operator == operators.eq:
                cols = util.column_set(chain(*[c.proxy_set for c in columns.difference(omit)]))
                if binary.left in cols and binary.right in cols:
                    for c in columns:
                        if c.shares_lineage(binary.right):
                            omit.add(c)
                            break

        for clause in clauses:
            visitors.traverse(clause, {}, {"binary": visit_binary})

    return expression.ColumnSet(columns.difference(omit))
Example #24
0
    def __create_lazy_clause(cls, prop, reverse_direction=False):
        binds = {}
        equated_columns = {}

        secondaryjoin = prop.secondaryjoin
        equated = dict(prop.local_remote_pairs)

        def should_bind(targetcol, othercol):
            if reverse_direction and not secondaryjoin:
                return othercol in equated
            else:
                return targetcol in equated

        def visit_binary(binary):
            leftcol = binary.left
            rightcol = binary.right

            equated_columns[rightcol] = leftcol
            equated_columns[leftcol] = rightcol

            if should_bind(leftcol, rightcol):
                if leftcol not in binds:
                    binds[leftcol] = sql.bindparam(None,
                                                   None,
                                                   type_=binary.right.type)
                binary.left = binds[leftcol]
            elif should_bind(rightcol, leftcol):
                if rightcol not in binds:
                    binds[rightcol] = sql.bindparam(None,
                                                    None,
                                                    type_=binary.left.type)
                binary.right = binds[rightcol]

        lazywhere = prop.primaryjoin

        if not prop.secondaryjoin or not reverse_direction:
            lazywhere = visitors.traverse(lazywhere,
                                          clone=True,
                                          visit_binary=visit_binary)

        if prop.secondaryjoin is not None:
            if reverse_direction:
                secondaryjoin = visitors.traverse(secondaryjoin,
                                                  clone=True,
                                                  visit_binary=visit_binary)
            lazywhere = sql.and_(lazywhere, secondaryjoin)

        bind_to_col = dict([(binds[col].key, col) for col in binds])

        return (lazywhere, bind_to_col, equated_columns)
Example #25
0
    def _lazy_none_clause(self, reverse_direction=False):
        if not reverse_direction:
            (criterion, bind_to_col,
             rev) = (self.__lazywhere, self.__bind_to_col,
                     self._equated_columns)
        else:
            (criterion, bind_to_col, rev) = LazyLoader.__create_lazy_clause(
                self.parent_property, reverse_direction=reverse_direction)

        def visit_binary(binary):
            mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent
            if isinstance(binary.left, expression._BindParamClause
                          ) and binary.left.key in bind_to_col:
                # reverse order if the NULL is on the left side
                binary.left = binary.right
                binary.right = expression.null()
                binary.operator = operators.is_
            elif isinstance(binary.right, expression._BindParamClause
                            ) and binary.right.key in bind_to_col:
                binary.right = expression.null()
                binary.operator = operators.is_

        return visitors.traverse(criterion,
                                 clone=True,
                                 visit_binary=visit_binary)
Example #26
0
def sort_tables(tables):
    """sort a collection of Table objects in order of their foreign-key dependency."""

    tables = list(tables)
    tuples = []
    def visit_foreign_key(fkey):
        if fkey.use_alter:
            return
        parent_table = fkey.column.table
        if parent_table in tables:
            child_table = fkey.parent.table
            tuples.append( ( parent_table, child_table ) )

    for table in tables:
        visitors.traverse(table, {'schema_visitor':True}, {'foreign_key':visit_foreign_key})
    return topological.sort(tuples, tables)
Example #27
0
def _get_select_comparisons(statement):
    """Search a Select or Query object for binary expressions.

    Returns expressions which match a Column against one or more
    literal values as a list of tuples of the form
    (column, operator, values).   "values" is a single value
    or tuple of values depending on the operator.

    """
    binds = {}
    clauses = set()
    comparisons = []

    def visit_bindparam(bind):
        # visit a bind parameter.

        value = bind.effective_value
        binds[bind] = value

    def visit_column(column):
        clauses.add(column)

    def visit_binary(binary):
        if binary.left in clauses and binary.right in binds:
            comparisons.append(
                (binary.left, binary.operator, binds[binary.right]))

        elif binary.left in binds and binary.right in clauses:
            comparisons.append(
                (binary.right, binary.operator, binds[binary.left]))

    # here we will traverse through the query's criterion, searching
    # for SQL constructs.  We will place simple column comparisons
    # into a list.
    if statement.whereclause is not None:
        visitors.traverse(
            statement.whereclause,
            {},
            {
                "bindparam": visit_bindparam,
                "binary": visit_binary,
                "column": visit_column,
            },
        )
    return comparisons
Example #28
0
    def _get_nonansi_join_whereclause(self, froms):
        clauses = []

        def visit_join(join):
            if join.isouter:
                def visit_binary(binary):
                    if binary.operator == sql_operators.eq:
                        if binary.left.table is join.right:
                            binary.left = _OuterJoinColumn(binary.left)
                        elif binary.right.table is join.right:
                            binary.right = _OuterJoinColumn(binary.right)
                clauses.append(visitors.cloned_traverse(join.onclause, {}, {'binary':visit_binary}))
            else:
                clauses.append(join.onclause)

        for f in froms:
            visitors.traverse(f, {}, {'join':visit_join})
        return sql.and_(*clauses)
    def _get_nonansi_join_whereclause(self, froms):
        clauses = []

        def visit_join(join):
            if join.isouter:
                def visit_binary(binary):
                    if binary.operator == sql_operators.eq:
                        if binary.left.table is join.right:
                            binary.left = _OuterJoinColumn(binary.left)
                        elif binary.right.table is join.right:
                            binary.right = _OuterJoinColumn(binary.right)
                clauses.append(visitors.cloned_traverse(join.onclause, {}, {'binary':visit_binary}))
            else:
                clauses.append(join.onclause)

        for f in froms:
            visitors.traverse(f, {}, {'join':visit_join})
        return sql.and_(*clauses)
Example #30
0
File: util.py Project: Kellel/items
def bind_values(clause):
    """Return an ordered list of "bound" values in the given clause.

    E.g.::

        >>> expr = and_(
        ...    table.c.foo==5, table.c.foo==7
        ... )
        >>> bind_values(expr)
        [5, 7]
    """

    v = []
    def visit_bindparam(bind):
        v.append(bind.effective_value)

    visitors.traverse(clause, {}, {'bindparam':visit_bindparam})
    return v
Example #31
0
def folded_equivalents(join, equivs=None):
    """Return a list of uniquely named columns.

    The column list of the given Join will be narrowed 
    down to a list of all equivalently-named,
    equated columns folded into one column, where 'equated' means they are
    equated to each other in the ON clause of this join.

    This function is used by Join.select(fold_equivalents=True).

    Deprecated.   This function is used for a certain kind of 
    "polymorphic_union" which is designed to achieve joined
    table inheritance where the base table has no "discriminator"
    column; [ticket:1131] will provide a better way to 
    achieve this.

    """
    if equivs is None:
        equivs = set()

    def visit_binary(binary):
        if binary.operator == operators.eq and binary.left.name == binary.right.name:
            equivs.add(binary.right)
            equivs.add(binary.left)

    visitors.traverse(join.onclause, {}, {"binary": visit_binary})
    collist = []
    if isinstance(join.left, expression.Join):
        left = folded_equivalents(join.left, equivs)
    else:
        left = list(join.left.columns)
    if isinstance(join.right, expression.Join):
        right = folded_equivalents(join.right, equivs)
    else:
        right = list(join.right.columns)
    used = set()
    for c in left + right:
        if c in equivs:
            if c.name not in used:
                collist.append(c)
                used.add(c.name)
        else:
            collist.append(c)
    return collist
Example #32
0
def folded_equivalents(join, equivs=None):
    """Return a list of uniquely named columns.
    
    The column list of the given Join will be narrowed 
    down to a list of all equivalently-named,
    equated columns folded into one column, where 'equated' means they are
    equated to each other in the ON clause of this join.

    This function is used by Join.select(fold_equivalents=True).
    
    Deprecated.   This function is used for a certain kind of 
    "polymorphic_union" which is designed to achieve joined
    table inheritance where the base table has no "discriminator"
    column; [ticket:1131] will provide a better way to 
    achieve this.

    """
    if equivs is None:
        equivs = set()

    def visit_binary(binary):
        if binary.operator == operators.eq and binary.left.name == binary.right.name:
            equivs.add(binary.right)
            equivs.add(binary.left)

    visitors.traverse(join.onclause, {}, {'binary': visit_binary})
    collist = []
    if isinstance(join.left, expression.Join):
        left = folded_equivalents(join.left, equivs)
    else:
        left = list(join.left.columns)
    if isinstance(join.right, expression.Join):
        right = folded_equivalents(join.right, equivs)
    else:
        right = list(join.right.columns)
    used = set()
    for c in left + right:
        if c in equivs:
            if c.name not in used:
                collist.append(c)
                used.add(c.name)
        else:
            collist.append(c)
    return collist
Example #33
0
def reduce_columns(columns, *clauses):
    """given a list of columns, return a 'reduced' set based on natural equivalents.

    the set is reduced to the smallest list of columns which have no natural
    equivalent present in the list.  A "natural equivalent" means that two columns
    will ultimately represent the same value because they are related by a foreign key.

    \*clauses is an optional list of join clauses which will be traversed
    to further identify columns that are "equivalent".

    This function is primarily used to determine the most minimal "primary key"
    from a selectable, by reducing the set of primary key columns present
    in the the selectable to just those that are not repeated.

    """

    columns = util.OrderedSet(columns)

    omit = util.Set()
    for col in columns:
        for fk in col.foreign_keys:
            for c in columns:
                if c is col:
                    continue
                if fk.column.shares_lineage(c):
                    omit.add(col)
                    break

    if clauses:

        def visit_binary(binary):
            if binary.operator == operators.eq:
                cols = util.Set(
                    chain(*[c.proxy_set for c in columns.difference(omit)]))
                if binary.left in cols and binary.right in cols:
                    for c in columns:
                        if c.shares_lineage(binary.right):
                            omit.add(c)
                            break

        for clause in clauses:
            visitors.traverse(clause, visit_binary=visit_binary)

    return expression.ColumnSet(columns.difference(omit))
Example #34
0
    def __create_lazy_clause(cls, prop, reverse_direction=False):
        binds = {}
        equated_columns = {}

        secondaryjoin = prop.secondaryjoin
        equated = dict(prop.local_remote_pairs)
        
        def should_bind(targetcol, othercol):
            if reverse_direction and not secondaryjoin:
                return othercol in equated
            else:
                return targetcol in equated

        def visit_binary(binary):
            leftcol = binary.left
            rightcol = binary.right

            equated_columns[rightcol] = leftcol
            equated_columns[leftcol] = rightcol

            if should_bind(leftcol, rightcol):
                if leftcol not in binds:
                    binds[leftcol] = sql.bindparam(None, None, type_=binary.right.type)
                binary.left = binds[leftcol]
            elif should_bind(rightcol, leftcol):
                if rightcol not in binds:
                    binds[rightcol] = sql.bindparam(None, None, type_=binary.left.type)
                binary.right = binds[rightcol]

        lazywhere = prop.primaryjoin
        
        if not prop.secondaryjoin or not reverse_direction:
            lazywhere = visitors.traverse(lazywhere, clone=True, visit_binary=visit_binary)
        
        if prop.secondaryjoin is not None:
            if reverse_direction:
                secondaryjoin = visitors.traverse(secondaryjoin, clone=True, visit_binary=visit_binary)
            lazywhere = sql.and_(lazywhere, secondaryjoin)
    
        bind_to_col = dict([(binds[col].key, col) for col in binds])
        
        return (lazywhere, bind_to_col, equated_columns)
Example #35
0
 def visit_join(join):
     if join.isouter:
         def visit_binary(binary):
             if binary.operator == sql_operators.eq:
                 if binary.left.table is join.right:
                     binary.left = _OuterJoinColumn(binary.left)
                 elif binary.right.table is join.right:
                     binary.right = _OuterJoinColumn(binary.right)
         clauses.append(visitors.traverse(join.onclause, visit_binary=visit_binary, clone=True))
     else:
         clauses.append(join.onclause)
Example #36
0
def reduce_columns(columns, *clauses):
    """given a list of columns, return a 'reduced' set based on natural equivalents.

    the set is reduced to the smallest list of columns which have no natural
    equivalent present in the list.  A "natural equivalent" means that two columns
    will ultimately represent the same value because they are related by a foreign key.

    \*clauses is an optional list of join clauses which will be traversed
    to further identify columns that are "equivalent".

    This function is primarily used to determine the most minimal "primary key"
    from a selectable, by reducing the set of primary key columns present
    in the the selectable to just those that are not repeated.

    """

    columns = util.OrderedSet(columns)

    omit = util.Set()
    for col in columns:
        for fk in col.foreign_keys:
            for c in columns:
                if c is col:
                    continue
                if fk.column.shares_lineage(c):
                    omit.add(col)
                    break

    if clauses:
        def visit_binary(binary):
            if binary.operator == operators.eq:
                cols = util.Set(chain(*[c.proxy_set for c in columns.difference(omit)]))
                if binary.left in cols and binary.right in cols:
                    for c in columns:
                        if c.shares_lineage(binary.right):
                            omit.add(c)
                            break
        for clause in clauses:
            visitors.traverse(clause, visit_binary=visit_binary)

    return expression.ColumnSet(columns.difference(omit))
Example #37
0
def find_tables(clause, check_columns=False, include_aliases=False):
    """locate Table objects within the given expression."""
    
    tables = []
    kwargs = {}
    if include_aliases:
        def visit_alias(alias):
            tables.append(alias)
        kwargs['visit_alias']  = visit_alias

    if check_columns:
        def visit_column(column):
            tables.append(column.table)
        kwargs['visit_column'] = visit_column

    def visit_table(table):
        tables.append(table)
    kwargs['visit_table'] = visit_table

    visitors.traverse(clause, traverse_options= {'column_collections':False}, **kwargs)
    return tables
Example #38
0
    def __create_lazy_clause(cls, prop, reverse_direction=False):
        binds = {}
        lookup = {}
        equated_columns = {}

        if reverse_direction and not prop.secondaryjoin:
            for l, r in prop.local_remote_pairs:
                _list = lookup.setdefault(r, [])
                _list.append((r, l))
                equated_columns[l] = r
        else:
            for l, r in prop.local_remote_pairs:
                _list = lookup.setdefault(l, [])
                _list.append((l, r))
                equated_columns[r] = l
                
        def col_to_bind(col):
            if col in lookup:
                for tobind, equated in lookup[col]:
                    if equated in binds:
                        return None
                if col not in binds:
                    binds[col] = sql.bindparam(None, None, type_=col.type)
                return binds[col]
            return None
                    
        lazywhere = prop.primaryjoin
        
        if not prop.secondaryjoin or not reverse_direction:
            lazywhere = visitors.traverse(lazywhere, before_clone=col_to_bind, clone=True) 
        
        if prop.secondaryjoin is not None:
            secondaryjoin = prop.secondaryjoin
            if reverse_direction:
                secondaryjoin = visitors.traverse(secondaryjoin, before_clone=col_to_bind, clone=True)
            lazywhere = sql.and_(lazywhere, secondaryjoin)
    
        bind_to_col = dict([(binds[col].key, col) for col in binds])
        
        return (lazywhere, bind_to_col, equated_columns)
Example #39
0
    def _sql_handler (self, *clauses):
        if not clauses:
            return self
        
        if self.func_name in map(lambda a:a[0],self.func_clauses):
            raise Exception, "Generative function specified more than once"

        tables = []
        def check_unique_table(column):
            if tables and column.table not in tables:
                raise NotImplementedError("Can't join indices yet")
            tables.append(column.table)
        for clause in clauses:
            visitors.traverse(clause, {}, {'column': functools.partial(check_unique_table)})
        assert tables

        if not self.func_table:
            self.func_table = tables[0]
        else:
            assert self.func_table == tables[0], "Can't join indices yet"
        self.func_clauses.append ((self.func_name,clauses))
        self.func_name = None
        return self
Example #40
0
def folded_equivalents(join, equivs=None):
    """Returns the column list of the given Join with all equivalently-named,
    equated columns folded into one column, where 'equated' means they are
    equated to each other in the ON clause of this join.

    This function is used by Join.select(fold_equivalents=True).
    
    TODO: deprecate ?
    """

    if equivs is None:
        equivs = util.Set()

    def visit_binary(binary):
        if binary.operator == operators.eq and binary.left.name == binary.right.name:
            equivs.add(binary.right)
            equivs.add(binary.left)

    visitors.traverse(join.onclause, visit_binary=visit_binary)
    collist = []
    if isinstance(join.left, expression.Join):
        left = folded_equivalents(join.left, equivs)
    else:
        left = list(join.left.columns)
    if isinstance(join.right, expression.Join):
        right = folded_equivalents(join.right, equivs)
    else:
        right = list(join.right.columns)
    used = util.Set()
    for c in left + right:
        if c in equivs:
            if c.name not in used:
                collist.append(c)
                used.add(c.name)
        else:
            collist.append(c)
    return collist
Example #41
0
def compute_dependencies(tables):
    """Construct a reverse dependency graph for the given tables.

    Returns a dict which maps a table to the list of tables which depend on it.
    """
    tables = list(tables)
    graph = {}

    def visit_foreign_key(fkey):
        if fkey.use_alter:
            return
        parent_table = fkey.column.table
        if parent_table in tables:
            child_table = fkey.parent.table
            if parent_table is not child_table:
                graph.setdefault(parent_table, []).append(child_table)

    for table in tables:
        visitors.traverse(table, {'schema_visitor': True},
                          {'foreign_key': visit_foreign_key})

        graph.setdefault(table, []).extend(table._extra_dependencies)

    return graph
Example #42
0
def compute_dependencies(tables):
    """Construct a reverse dependency graph for the given tables.

    Returns a dict which maps a table to the list of tables which depend on it.
    """
    tables = list(tables)
    graph = {}
    def visit_foreign_key(fkey):
        if fkey.use_alter:
            return
        parent_table = fkey.column.table
        if parent_table in tables:
            child_table = fkey.parent.table
            if parent_table is not child_table:
                graph.setdefault(parent_table, []).append(child_table)

    for table in tables:
        visitors.traverse(table,
                          {'schema_visitor': True},
                          {'foreign_key': visit_foreign_key})

        graph.setdefault(table, []).extend(table._extra_dependencies)

    return graph
Example #43
0
        def visit_join(join):
            if join.isouter:

                def visit_binary(binary):
                    if binary.operator == sql_operators.eq:
                        if binary.left.table is join.right:
                            binary.left = _OuterJoinColumn(binary.left)
                        elif binary.right.table is join.right:
                            binary.right = _OuterJoinColumn(binary.right)

                clauses.append(
                    visitors.traverse(join.onclause,
                                      visit_binary=visit_binary,
                                      clone=True))
            else:
                clauses.append(join.onclause)
Example #44
0
    def lazy_clause(self, instance, reverse_direction=False):
        if instance is None:
            return self._lazy_none_clause(reverse_direction)
            
        if not reverse_direction:
            (criterion, bind_to_col, rev) = (self.__lazywhere, self.__bind_to_col, self._equated_columns)
        else:
            (criterion, bind_to_col, rev) = LazyLoader.__create_lazy_clause(self.parent_property, reverse_direction=reverse_direction)

        def visit_bindparam(bindparam):
            mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent
            if bindparam.key in bind_to_col:
                # use the "committed" (database) version to get query column values
                # also its a deferred value; so that when used by Query, the committed value is used
                # after an autoflush occurs
                bindparam.value = lambda: mapper._get_committed_attr_by_column(instance, bind_to_col[bindparam.key])
        return visitors.traverse(criterion, clone=True, visit_bindparam=visit_bindparam)
Example #45
0
    def _lazy_none_clause(self, reverse_direction=False):
        if not reverse_direction:
            (criterion, bind_to_col, rev) = (self.__lazywhere, self.__bind_to_col, self._equated_columns)
        else:
            (criterion, bind_to_col, rev) = LazyLoader.__create_lazy_clause(self.parent_property, reverse_direction=reverse_direction)

        def visit_binary(binary):
            mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent
            if isinstance(binary.left, expression._BindParamClause) and binary.left.key in bind_to_col:
                # reverse order if the NULL is on the left side
                binary.left = binary.right
                binary.right = expression.null()
                binary.operator = operators.is_
            elif isinstance(binary.right, expression._BindParamClause) and binary.right.key in bind_to_col:
                binary.right = expression.null()
                binary.operator = operators.is_
        
        return visitors.traverse(criterion, clone=True, visit_binary=visit_binary)
Example #46
0
    def lazy_clause(self, instance, reverse_direction=False, alias_secondary=False):
        if instance is None:
            return self._lazy_none_clause(reverse_direction)
            
        if not reverse_direction:
            (criterion, bind_to_col, rev) = (self.__lazywhere, self.__bind_to_col, self._equated_columns)
        else:
            (criterion, bind_to_col, rev) = LazyLoader.__create_lazy_clause(self.parent_property, reverse_direction=reverse_direction)

        def visit_bindparam(bindparam):
            mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent
            if bindparam.key in bind_to_col:
                # use the "committed" (database) version to get query column values
                # also its a deferred value; so that when used by Query, the committed value is used
                # after an autoflush occurs
                bindparam.value = lambda: mapper._get_committed_attr_by_column(instance, bind_to_col[bindparam.key])
                
        if self.secondary and alias_secondary:
            criterion = sql_util.ClauseAdapter(self.secondary.alias()).traverse(criterion)
            
        return visitors.traverse(criterion, clone=True, visit_bindparam=visit_bindparam)
Example #47
0
    def lazy_clause(self, instance, reverse_direction=False):
        if instance is None:
            return self._lazy_none_clause(reverse_direction)

        if not reverse_direction:
            (criterion, lazybinds, rev) = (self.lazywhere, self.lazybinds,
                                           self.equated_columns)
        else:
            (criterion, lazybinds, rev) = LazyLoader._create_lazy_clause(
                self.parent_property, reverse_direction=reverse_direction)
        bind_to_col = dict([(lazybinds[col].key, col) for col in lazybinds])

        def visit_bindparam(bindparam):
            mapper = reverse_direction and self.parent_property.mapper or self.parent_property.parent
            if bindparam.key in bind_to_col:
                # use the "committed" (database) version to get query column values
                bindparam.value = mapper._get_committed_attr_by_column(
                    instance, bind_to_col[bindparam.key])

        return visitors.traverse(criterion,
                                 clone=True,
                                 visit_bindparam=visit_bindparam)
def _find_columns(clause):
    """locate Column objects within the given expression."""

    cols = set()
    traverse(clause, {}, {'column': cols.add})
    return cols
Example #49
0
    def compile(self, sqlclause, foreign_keys=None, issecondary=None):
        def compile_binary(binary):
            """Assemble a SyncRule given a single binary condition."""

            if binary.operator != operators.eq or not isinstance(
                    binary.left, schema.Column) or not isinstance(
                        binary.right, schema.Column):
                return

            source_column = None
            dest_column = None

            if foreign_keys is None:
                if binary.left.table == binary.right.table:
                    raise exceptions.ArgumentError(
                        "need foreign_keys argument for self-referential sync")

                if binary.left in util.Set(
                    [f.column for f in binary.right.foreign_keys]):
                    dest_column = binary.right
                    source_column = binary.left
                elif binary.right in util.Set(
                    [f.column for f in binary.left.foreign_keys]):
                    dest_column = binary.left
                    source_column = binary.right
            else:
                if binary.left in foreign_keys:
                    source_column = binary.right
                    dest_column = binary.left
                elif binary.right in foreign_keys:
                    source_column = binary.left
                    dest_column = binary.right

            if source_column and dest_column:
                if self.direction == ONETOMANY:
                    self.syncrules.append(
                        SyncRule(self.parent_mapper,
                                 source_column,
                                 dest_column,
                                 dest_mapper=self.child_mapper))
                elif self.direction == MANYTOONE:
                    self.syncrules.append(
                        SyncRule(self.child_mapper,
                                 source_column,
                                 dest_column,
                                 dest_mapper=self.parent_mapper))
                else:
                    if not issecondary:
                        self.syncrules.append(
                            SyncRule(self.parent_mapper,
                                     source_column,
                                     dest_column,
                                     dest_mapper=self.child_mapper,
                                     issecondary=issecondary))
                    else:
                        self.syncrules.append(
                            SyncRule(self.child_mapper,
                                     source_column,
                                     dest_column,
                                     dest_mapper=self.parent_mapper,
                                     issecondary=issecondary))

        rules_added = len(self.syncrules)
        visitors.traverse(sqlclause, visit_binary=compile_binary)
        if len(self.syncrules) == rules_added:
            raise exceptions.ArgumentError(
                "No syncrules generated for join criterion " + str(sqlclause))
Example #50
0
def _find_columns(clause):
    """locate Column objects within the given expression."""

    cols = set()
    traverse(clause, {}, {"column": cols.add})
    return cols
Example #51
0
def find_columns(clause):
    """locate Column objects within the given expression."""

    cols = util.column_set()
    visitors.traverse(clause, {}, {"column": cols.add})
    return cols
    def _run_cache_key_fixture(self, fixture, compare_values):
        case_a = fixture()
        case_b = fixture()

        for a, b in itertools.combinations_with_replacement(
                range(len(case_a)), 2):
            if a == b:
                a_key = case_a[a]._generate_cache_key()
                b_key = case_b[b]._generate_cache_key()

                if a_key is None:
                    assert case_a[a]._annotations.get("nocache")

                    assert b_key is None
                    continue

                eq_(a_key.key, b_key.key)
                eq_(hash(a_key.key), hash(b_key.key))

                for a_param, b_param in zip(a_key.bindparams,
                                            b_key.bindparams):
                    assert a_param.compare(b_param,
                                           compare_values=compare_values)
            else:
                a_key = case_a[a]._generate_cache_key()
                b_key = case_b[b]._generate_cache_key()

                if a_key is None or b_key is None:
                    if a_key is None:
                        assert case_a[a]._annotations.get("nocache")
                    if b_key is None:
                        assert case_b[b]._annotations.get("nocache")
                    continue

                if a_key.key == b_key.key:
                    for a_param, b_param in zip(a_key.bindparams,
                                                b_key.bindparams):
                        if not a_param.compare(b_param,
                                               compare_values=compare_values):
                            break
                    else:
                        # this fails unconditionally since we could not
                        # find bound parameter values that differed.
                        # Usually we intended to get two distinct keys here
                        # so the failure will be more descriptive using the
                        # ne_() assertion.
                        ne_(a_key.key, b_key.key)
                else:
                    ne_(a_key.key, b_key.key)

            # ClauseElement-specific test to ensure the cache key
            # collected all the bound parameters
            if isinstance(case_a[a], ClauseElement) and isinstance(
                    case_b[b], ClauseElement):
                assert_a_params = []
                assert_b_params = []
                visitors.traverse(case_a[a], {},
                                  {"bindparam": assert_a_params.append})
                visitors.traverse(case_b[b], {},
                                  {"bindparam": assert_b_params.append})

                # note we're asserting the order of the params as well as
                # if there are dupes or not.  ordering has to be
                # deterministic and matches what a traversal would provide.
                eq_(
                    sorted(a_key.bindparams, key=lambda b: b.key),
                    sorted(util.unique_list(assert_a_params),
                           key=lambda b: b.key),
                )
                eq_(
                    sorted(b_key.bindparams, key=lambda b: b.key),
                    sorted(util.unique_list(assert_b_params),
                           key=lambda b: b.key),
                )