示例#1
0
    def buildSQLExpression(self, sql_catalog, column_map, only_group_columns,
                           group):
        """
      Render RelatedKey's ZSQLMethod by providing it table aliases from
      ColumnMap.

      sql_catalog (SQLCatalog)
      column_map (ColumnMap)
      group (string)
      only_group_columns (bool)
        Ignored.
    """
        related_key = getattr(sql_catalog, self.related_key_id)

        # related key is defined in catalog
        related_table_list, destination_table = self.table_list[:
                                                                -1], self.table_list[
                                                                    -1]

        # method caching
        getTableAlias = column_map.getTableAlias
        getRelatedKeyGroup = column_map.getRelatedKeyGroup

        # table aliases for related tables
        table_alias_list = [
            (getTableAlias(related_table,
                           group=getRelatedKeyGroup(index,
                                                    group)), related_table)
            for (index, related_table) in enumerate(related_table_list)
        ]
        # table alias for destination table
        table_alias_list.append(
            (getTableAlias(destination_table, group=group), destination_table))

        # map aliases to use in ZSQLMethod.
        table_alias_dict = dict(
            ('table_%s' % (index, ), table_alias)
            for (index, (table_alias,
                         table_name)) in enumerate(table_alias_list))

        assert len(table_alias_list) == len(table_alias_dict)

        query_table = column_map.getCatalogTableAlias()
        rendered_related_key = related_key(
            query_table=query_table,
            RELATED_QUERY_SEPARATOR=RELATED_QUERY_SEPARATOR,
            src__=1,
            **table_alias_dict)
        join_condition_list = rendered_related_key.split(
            RELATED_QUERY_SEPARATOR)

        # Important:
        # Previously the catalog separated join condition from the related query.
        # Example:
        #   ComplexQuery(Query(title="foo"),
        #                Query(subordination_title="bar")
        #                , operator='OR')
        # Former catalog rendering (truncated where-expression):
        #   AND ((catalog.title LIKE '%foo%') OR
        #        (related_catalog_1.title LIKE '%bar%'))
        #   AND (related_catalog_1.uid = related_category_0.category_uid AND
        #        related_category_0.base_category_uid = 873 AND
        #        related_category_0.uid = catalog.uid)
        # As you can see, the part of the query joining the tables is *out* of the
        # OR expression, and therefor applies to the entire query.
        # This was done on purpose, because doing otherwise gives very poor
        # performances (on a simple data set, similar query can take *minutes* to
        # execute - as of MySQL 5.x).
        #
        # Because of this, we never return an SQLExpression here, as it
        # would mix join definition with column condition in the body of
        # the WHERE clause. Instead we explicitly define a Join to the
        # catalog. The ColumnMap defines whether this is an Inner Join or
        # a Left Outer Join. Notice that if an Inner Join is decided,
        # objects lacking a relationship will never appear in the result.

        if len(join_condition_list) == len(table_alias_list):
            # Good! we got a compatible method that splits the join
            # conditions according to the related tables.
            #
            # Add a join on this related key, based on the chain of
            # inner-joins of the related key tables.
            query_table_join_condition = join_condition_list.pop()
            right_side = self.stitchJoinDefinition(table_alias_list,
                                                   join_condition_list,
                                                   column_map)
            column_map.addRelatedKeyJoin(self.column,
                                         right_side=right_side,
                                         condition=query_table_join_condition)
        else:
            # Method did not render the related key condition with the
            # appropriate separators so we could split it

            # XXX: Can we try to parse rendered_related_key to select which
            # conditions go with each table? Maybe we could still use
            # explicit joins this way...

            msg = RELATED_KEY_MISMATCH_MESSAGE % (
                self.related_key_id, self.column, table_alias_list,
                rendered_related_key)
            if BACKWARD_COMPATIBILITY:
                # BBB: remove this branch of the condition, and the above
                # constant, when all zsql_methods have been adapted to return
                # the join queries properly separated by the
                # RELATED_QUERY_SEPARATOR.

                # The rendered related key doesn't have the separators for each
                # joined table, so we revert to doing implicit inner joins:
                log.warning(msg + "\n\nAdding an Implicit Join Condition...")
                column_map._addJoinQueryForColumn(
                    self.column, SQLQuery(rendered_related_key))
            else:
                raise RuntimeError(msg)
        return None
示例#2
0
 def _extendJoinConditionQueryList(self, query_list):
     self.left_tabledef._extendJoinConditionQueryList(query_list)
     self.right_tabledef._extendJoinConditionQueryList(query_list)
     query_list.append(SQLQuery(self.condition))