Search in sources :

Example 1 with HashSubPlan

use of org.apache.phoenix.execute.HashJoinPlan.HashSubPlan in project phoenix by apache.

the class QueryCompiler method compileJoinQuery.

protected QueryPlan compileJoinQuery(JoinCompiler.Strategy strategy, StatementContext context, List<Object> binds, JoinTable joinTable, boolean asSubquery, boolean projectPKColumns, List<OrderByNode> orderBy) throws SQLException {
    byte[] emptyByteArray = new byte[0];
    List<JoinSpec> joinSpecs = joinTable.getJoinSpecs();
    switch(strategy) {
        case HASH_BUILD_RIGHT:
            {
                boolean[] starJoinVector = joinTable.getStarJoinVector();
                Table table = joinTable.getTable();
                PTable initialProjectedTable;
                TableRef tableRef;
                SelectStatement query;
                TupleProjector tupleProjector;
                if (!table.isSubselect()) {
                    context.setCurrentTable(table.getTableRef());
                    initialProjectedTable = table.createProjectedTable(!projectPKColumns, context);
                    tableRef = table.getTableRef();
                    table.projectColumns(context.getScan());
                    query = joinTable.getAsSingleSubquery(table.getAsSubquery(orderBy), asSubquery);
                    tupleProjector = new TupleProjector(initialProjectedTable);
                } else {
                    SelectStatement subquery = table.getAsSubquery(orderBy);
                    QueryPlan plan = compileSubquery(subquery, false);
                    initialProjectedTable = table.createProjectedTable(plan.getProjector());
                    tableRef = plan.getTableRef();
                    context.getScan().setFamilyMap(plan.getContext().getScan().getFamilyMap());
                    query = joinTable.getAsSingleSubquery((SelectStatement) plan.getStatement(), asSubquery);
                    tupleProjector = new TupleProjector(plan.getProjector());
                }
                context.setCurrentTable(tableRef);
                PTable projectedTable = initialProjectedTable;
                int count = joinSpecs.size();
                ImmutableBytesPtr[] joinIds = new ImmutableBytesPtr[count];
                List<Expression>[] joinExpressions = new List[count];
                JoinType[] joinTypes = new JoinType[count];
                PTable[] tables = new PTable[count];
                int[] fieldPositions = new int[count];
                StatementContext[] subContexts = new StatementContext[count];
                QueryPlan[] subPlans = new QueryPlan[count];
                HashSubPlan[] hashPlans = new HashSubPlan[count];
                fieldPositions[0] = projectedTable.getColumns().size() - projectedTable.getPKColumns().size();
                for (int i = 0; i < count; i++) {
                    JoinSpec joinSpec = joinSpecs.get(i);
                    Scan subScan = ScanUtil.newScan(originalScan);
                    subContexts[i] = new StatementContext(statement, context.getResolver(), subScan, new SequenceManager(statement));
                    subPlans[i] = compileJoinQuery(subContexts[i], binds, joinSpec.getJoinTable(), true, true, null);
                    boolean hasPostReference = joinSpec.getJoinTable().hasPostReference();
                    if (hasPostReference) {
                        tables[i] = subContexts[i].getResolver().getTables().get(0).getTable();
                        projectedTable = JoinCompiler.joinProjectedTables(projectedTable, tables[i], joinSpec.getType());
                    } else {
                        tables[i] = null;
                    }
                }
                for (int i = 0; i < count; i++) {
                    JoinSpec joinSpec = joinSpecs.get(i);
                    context.setResolver(FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), query.getUdfParseNodes()));
                    // place-holder
                    joinIds[i] = new ImmutableBytesPtr(emptyByteArray);
                    Pair<List<Expression>, List<Expression>> joinConditions = joinSpec.compileJoinConditions(context, subContexts[i], strategy);
                    joinExpressions[i] = joinConditions.getFirst();
                    List<Expression> hashExpressions = joinConditions.getSecond();
                    Pair<Expression, Expression> keyRangeExpressions = new Pair<Expression, Expression>(null, null);
                    boolean optimized = getKeyExpressionCombinations(keyRangeExpressions, context, joinTable.getStatement(), tableRef, joinSpec.getType(), joinExpressions[i], hashExpressions);
                    Expression keyRangeLhsExpression = keyRangeExpressions.getFirst();
                    Expression keyRangeRhsExpression = keyRangeExpressions.getSecond();
                    joinTypes[i] = joinSpec.getType();
                    if (i < count - 1) {
                        fieldPositions[i + 1] = fieldPositions[i] + (tables[i] == null ? 0 : (tables[i].getColumns().size() - tables[i].getPKColumns().size()));
                    }
                    hashPlans[i] = new HashSubPlan(i, subPlans[i], optimized ? null : hashExpressions, joinSpec.isSingleValueOnly(), keyRangeLhsExpression, keyRangeRhsExpression);
                }
                TupleProjector.serializeProjectorIntoScan(context.getScan(), tupleProjector);
                QueryPlan plan = compileSingleFlatQuery(context, query, binds, asSubquery, !asSubquery && joinTable.isAllLeftJoin(), null, !table.isSubselect() && projectPKColumns ? tupleProjector : null, true);
                Expression postJoinFilterExpression = joinTable.compilePostFilterExpression(context, table);
                Integer limit = null;
                Integer offset = null;
                if (!query.isAggregate() && !query.isDistinct() && query.getOrderBy().isEmpty()) {
                    limit = plan.getLimit();
                    offset = plan.getOffset();
                }
                HashJoinInfo joinInfo = new HashJoinInfo(projectedTable, joinIds, joinExpressions, joinTypes, starJoinVector, tables, fieldPositions, postJoinFilterExpression, QueryUtil.getOffsetLimit(limit, offset));
                return HashJoinPlan.create(joinTable.getStatement(), plan, joinInfo, hashPlans);
            }
        case HASH_BUILD_LEFT:
            {
                JoinSpec lastJoinSpec = joinSpecs.get(joinSpecs.size() - 1);
                JoinType type = lastJoinSpec.getType();
                JoinTable rhsJoinTable = lastJoinSpec.getJoinTable();
                Table rhsTable = rhsJoinTable.getTable();
                JoinTable lhsJoin = joinTable.getSubJoinTableWithoutPostFilters();
                Scan subScan = ScanUtil.newScan(originalScan);
                StatementContext lhsCtx = new StatementContext(statement, context.getResolver(), subScan, new SequenceManager(statement));
                QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, true, null);
                PTable rhsProjTable;
                TableRef rhsTableRef;
                SelectStatement rhs;
                TupleProjector tupleProjector;
                if (!rhsTable.isSubselect()) {
                    context.setCurrentTable(rhsTable.getTableRef());
                    rhsProjTable = rhsTable.createProjectedTable(!projectPKColumns, context);
                    rhsTableRef = rhsTable.getTableRef();
                    rhsTable.projectColumns(context.getScan());
                    rhs = rhsJoinTable.getAsSingleSubquery(rhsTable.getAsSubquery(orderBy), asSubquery);
                    tupleProjector = new TupleProjector(rhsProjTable);
                } else {
                    SelectStatement subquery = rhsTable.getAsSubquery(orderBy);
                    QueryPlan plan = compileSubquery(subquery, false);
                    rhsProjTable = rhsTable.createProjectedTable(plan.getProjector());
                    rhsTableRef = plan.getTableRef();
                    context.getScan().setFamilyMap(plan.getContext().getScan().getFamilyMap());
                    rhs = rhsJoinTable.getAsSingleSubquery((SelectStatement) plan.getStatement(), asSubquery);
                    tupleProjector = new TupleProjector(plan.getProjector());
                }
                context.setCurrentTable(rhsTableRef);
                context.setResolver(FromCompiler.getResolverForProjectedTable(rhsProjTable, context.getConnection(), rhs.getUdfParseNodes()));
                ImmutableBytesPtr[] joinIds = new ImmutableBytesPtr[] { new ImmutableBytesPtr(emptyByteArray) };
                Pair<List<Expression>, List<Expression>> joinConditions = lastJoinSpec.compileJoinConditions(lhsCtx, context, strategy);
                List<Expression> joinExpressions = joinConditions.getSecond();
                List<Expression> hashExpressions = joinConditions.getFirst();
                boolean needsMerge = lhsJoin.hasPostReference();
                PTable lhsTable = needsMerge ? lhsCtx.getResolver().getTables().get(0).getTable() : null;
                int fieldPosition = needsMerge ? rhsProjTable.getColumns().size() - rhsProjTable.getPKColumns().size() : 0;
                PTable projectedTable = needsMerge ? JoinCompiler.joinProjectedTables(rhsProjTable, lhsTable, type == JoinType.Right ? JoinType.Left : type) : rhsProjTable;
                TupleProjector.serializeProjectorIntoScan(context.getScan(), tupleProjector);
                context.setResolver(FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), rhs.getUdfParseNodes()));
                QueryPlan rhsPlan = compileSingleFlatQuery(context, rhs, binds, asSubquery, !asSubquery && type == JoinType.Right, null, !rhsTable.isSubselect() && projectPKColumns ? tupleProjector : null, true);
                Expression postJoinFilterExpression = joinTable.compilePostFilterExpression(context, rhsTable);
                Integer limit = null;
                Integer offset = null;
                if (!rhs.isAggregate() && !rhs.isDistinct() && rhs.getOrderBy().isEmpty()) {
                    limit = rhsPlan.getLimit();
                    offset = rhsPlan.getOffset();
                }
                HashJoinInfo joinInfo = new HashJoinInfo(projectedTable, joinIds, new List[] { joinExpressions }, new JoinType[] { type == JoinType.Right ? JoinType.Left : type }, new boolean[] { true }, new PTable[] { lhsTable }, new int[] { fieldPosition }, postJoinFilterExpression, QueryUtil.getOffsetLimit(limit, offset));
                Pair<Expression, Expression> keyRangeExpressions = new Pair<Expression, Expression>(null, null);
                getKeyExpressionCombinations(keyRangeExpressions, context, joinTable.getStatement(), rhsTableRef, type, joinExpressions, hashExpressions);
                return HashJoinPlan.create(joinTable.getStatement(), rhsPlan, joinInfo, new HashSubPlan[] { new HashSubPlan(0, lhsPlan, hashExpressions, false, keyRangeExpressions.getFirst(), keyRangeExpressions.getSecond()) });
            }
        case SORT_MERGE:
            {
                JoinTable lhsJoin = joinTable.getSubJoinTableWithoutPostFilters();
                JoinSpec lastJoinSpec = joinSpecs.get(joinSpecs.size() - 1);
                JoinType type = lastJoinSpec.getType();
                JoinTable rhsJoin = lastJoinSpec.getJoinTable();
                if (type == JoinType.Right) {
                    JoinTable temp = lhsJoin;
                    lhsJoin = rhsJoin;
                    rhsJoin = temp;
                }
                List<EqualParseNode> joinConditionNodes = lastJoinSpec.getOnConditions();
                List<OrderByNode> lhsOrderBy = Lists.<OrderByNode>newArrayListWithExpectedSize(joinConditionNodes.size());
                List<OrderByNode> rhsOrderBy = Lists.<OrderByNode>newArrayListWithExpectedSize(joinConditionNodes.size());
                for (EqualParseNode condition : joinConditionNodes) {
                    lhsOrderBy.add(NODE_FACTORY.orderBy(type == JoinType.Right ? condition.getRHS() : condition.getLHS(), false, true));
                    rhsOrderBy.add(NODE_FACTORY.orderBy(type == JoinType.Right ? condition.getLHS() : condition.getRHS(), false, true));
                }
                Scan lhsScan = ScanUtil.newScan(originalScan);
                StatementContext lhsCtx = new StatementContext(statement, context.getResolver(), lhsScan, new SequenceManager(statement));
                boolean preserveRowkey = !projectPKColumns && type != JoinType.Full;
                QueryPlan lhsPlan = compileJoinQuery(lhsCtx, binds, lhsJoin, true, !preserveRowkey, lhsOrderBy);
                PTable lhsProjTable = lhsCtx.getResolver().getTables().get(0).getTable();
                boolean isInRowKeyOrder = preserveRowkey && lhsPlan.getOrderBy().getOrderByExpressions().isEmpty();
                Scan rhsScan = ScanUtil.newScan(originalScan);
                StatementContext rhsCtx = new StatementContext(statement, context.getResolver(), rhsScan, new SequenceManager(statement));
                QueryPlan rhsPlan = compileJoinQuery(rhsCtx, binds, rhsJoin, true, true, rhsOrderBy);
                PTable rhsProjTable = rhsCtx.getResolver().getTables().get(0).getTable();
                Pair<List<Expression>, List<Expression>> joinConditions = lastJoinSpec.compileJoinConditions(type == JoinType.Right ? rhsCtx : lhsCtx, type == JoinType.Right ? lhsCtx : rhsCtx, strategy);
                List<Expression> lhsKeyExpressions = type == JoinType.Right ? joinConditions.getSecond() : joinConditions.getFirst();
                List<Expression> rhsKeyExpressions = type == JoinType.Right ? joinConditions.getFirst() : joinConditions.getSecond();
                boolean needsMerge = rhsJoin.hasPostReference();
                int fieldPosition = needsMerge ? lhsProjTable.getColumns().size() - lhsProjTable.getPKColumns().size() : 0;
                PTable projectedTable = needsMerge ? JoinCompiler.joinProjectedTables(lhsProjTable, rhsProjTable, type == JoinType.Right ? JoinType.Left : type) : lhsProjTable;
                ColumnResolver resolver = FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), joinTable.getStatement().getUdfParseNodes());
                TableRef tableRef = resolver.getTables().get(0);
                StatementContext subCtx = new StatementContext(statement, resolver, ScanUtil.newScan(originalScan), new SequenceManager(statement));
                subCtx.setCurrentTable(tableRef);
                QueryPlan innerPlan = new SortMergeJoinPlan(subCtx, joinTable.getStatement(), tableRef, type == JoinType.Right ? JoinType.Left : type, lhsPlan, rhsPlan, lhsKeyExpressions, rhsKeyExpressions, projectedTable, lhsProjTable, needsMerge ? rhsProjTable : null, fieldPosition, lastJoinSpec.isSingleValueOnly());
                context.setCurrentTable(tableRef);
                context.setResolver(resolver);
                TableNode from = NODE_FACTORY.namedTable(tableRef.getTableAlias(), NODE_FACTORY.table(tableRef.getTable().getSchemaName().getString(), tableRef.getTable().getTableName().getString()));
                ParseNode where = joinTable.getPostFiltersCombined();
                SelectStatement select = asSubquery ? NODE_FACTORY.select(from, joinTable.getStatement().getHint(), false, Collections.<AliasedNode>emptyList(), where, null, null, orderBy, null, null, 0, false, joinTable.getStatement().hasSequence(), Collections.<SelectStatement>emptyList(), joinTable.getStatement().getUdfParseNodes()) : NODE_FACTORY.select(joinTable.getStatement(), from, where);
                return compileSingleFlatQuery(context, select, binds, asSubquery, false, innerPlan, null, isInRowKeyOrder);
            }
        default:
            throw new IllegalArgumentException("Invalid join strategy '" + strategy + "'");
    }
}
Also used : TupleProjector(org.apache.phoenix.execute.TupleProjector) PTable(org.apache.phoenix.schema.PTable) HashSubPlan(org.apache.phoenix.execute.HashJoinPlan.HashSubPlan) SelectStatement(org.apache.phoenix.parse.SelectStatement) SortMergeJoinPlan(org.apache.phoenix.execute.SortMergeJoinPlan) SubqueryParseNode(org.apache.phoenix.parse.SubqueryParseNode) EqualParseNode(org.apache.phoenix.parse.EqualParseNode) ParseNode(org.apache.phoenix.parse.ParseNode) List(java.util.List) ArrayList(java.util.ArrayList) Pair(org.apache.hadoop.hbase.util.Pair) Table(org.apache.phoenix.compile.JoinCompiler.Table) JoinTable(org.apache.phoenix.compile.JoinCompiler.JoinTable) PTable(org.apache.phoenix.schema.PTable) ImmutableBytesPtr(org.apache.phoenix.hbase.index.util.ImmutableBytesPtr) JoinSpec(org.apache.phoenix.compile.JoinCompiler.JoinSpec) JoinType(org.apache.phoenix.parse.JoinTableNode.JoinType) Expression(org.apache.phoenix.expression.Expression) LiteralExpression(org.apache.phoenix.expression.LiteralExpression) RowValueConstructorExpression(org.apache.phoenix.expression.RowValueConstructorExpression) HashJoinInfo(org.apache.phoenix.join.HashJoinInfo) TableNode(org.apache.phoenix.parse.TableNode) Scan(org.apache.hadoop.hbase.client.Scan) TableRef(org.apache.phoenix.schema.TableRef) JoinTable(org.apache.phoenix.compile.JoinCompiler.JoinTable) EqualParseNode(org.apache.phoenix.parse.EqualParseNode)

Aggregations

ArrayList (java.util.ArrayList)1 List (java.util.List)1 Scan (org.apache.hadoop.hbase.client.Scan)1 Pair (org.apache.hadoop.hbase.util.Pair)1 JoinSpec (org.apache.phoenix.compile.JoinCompiler.JoinSpec)1 JoinTable (org.apache.phoenix.compile.JoinCompiler.JoinTable)1 Table (org.apache.phoenix.compile.JoinCompiler.Table)1 HashSubPlan (org.apache.phoenix.execute.HashJoinPlan.HashSubPlan)1 SortMergeJoinPlan (org.apache.phoenix.execute.SortMergeJoinPlan)1 TupleProjector (org.apache.phoenix.execute.TupleProjector)1 Expression (org.apache.phoenix.expression.Expression)1 LiteralExpression (org.apache.phoenix.expression.LiteralExpression)1 RowValueConstructorExpression (org.apache.phoenix.expression.RowValueConstructorExpression)1 ImmutableBytesPtr (org.apache.phoenix.hbase.index.util.ImmutableBytesPtr)1 HashJoinInfo (org.apache.phoenix.join.HashJoinInfo)1 EqualParseNode (org.apache.phoenix.parse.EqualParseNode)1 JoinType (org.apache.phoenix.parse.JoinTableNode.JoinType)1 ParseNode (org.apache.phoenix.parse.ParseNode)1 SelectStatement (org.apache.phoenix.parse.SelectStatement)1 SubqueryParseNode (org.apache.phoenix.parse.SubqueryParseNode)1