Search in sources :

Example 6 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.

the class StatementPartitioning method analyzeForMultiPartitionAccess.

/**
     * Given the query's list of tables and its collection(s) of equality-filtered columns and their equivalents,
     * determine whether all joins involving partitioned tables can be executed locally on a single partition.
     * This is only the case when they include equality comparisons between partition key columns.
     * VoltDB will reject joins of multiple partitioned tables unless all their partition keys are
     * constrained to be equal to each other.
     * Example: select * from T1, T2 where T1.ID = T2.ID
     * Additionally, in this case, there may be a constant equality filter on any of the columns,
     * which we want to extract as our SP partitioning parameter.
     *
     * @param tableAliasList The tables.
     * @param valueEquivalence Their column equality filters
     * @return the number of independently partitioned tables
     *         -- partitioned tables that aren't joined or filtered by the same value.
     *         The caller can raise an alarm if there is more than one.
     */
public void analyzeForMultiPartitionAccess(Collection<StmtTableScan> scans, HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence) {
    //* enable to debug */ System.out.println("DEBUG: analyze4MPAccess w/ scans:" + scans.size() + " filters:" + valueEquivalence.size());
    TupleValueExpression tokenPartitionKey = null;
    Set<Set<AbstractExpression>> eqSets = new HashSet<Set<AbstractExpression>>();
    int unfilteredPartitionKeyCount = 0;
    // reset this flag to forget the last result of the multiple partition access path.
    // AdHoc with parameters will call this function at least two times
    // By default this flag should be true.
    setJoinValid(true);
    setJoinInvalidReason(null);
    boolean subqueryHasReceiveNode = false;
    boolean hasPartitionedTableJoin = false;
    // Iterate over the tables to collect partition columns.
    for (StmtTableScan tableScan : scans) {
        // Replicated tables don't need filter coverage.
        if (tableScan.getIsReplicated()) {
            continue;
        }
        // The partition column can be null in an obscure edge case.
        // The table is declared non-replicated yet specifies no partitioning column.
        // This can occur legitimately when views based on partitioned tables neglect to group by the partition column.
        // The interpretation of this edge case is that the table has "randomly distributed data".
        // In such a case, the table is valid for use by MP queries only and can only be joined with replicated tables
        // because it has no recognized partitioning join key.
        List<SchemaColumn> columnsNeedingCoverage = tableScan.getPartitioningColumns();
        if (tableScan instanceof StmtSubqueryScan) {
            StmtSubqueryScan subScan = (StmtSubqueryScan) tableScan;
            subScan.promoteSinglePartitionInfo(valueEquivalence, eqSets);
            CompiledPlan subqueryPlan = subScan.getBestCostPlan();
            if ((!subScan.canRunInOneFragment()) || ((subqueryPlan != null) && subqueryPlan.rootPlanGraph.hasAnyNodeOfClass(AbstractReceivePlanNode.class))) {
                if (subqueryHasReceiveNode) {
                    // Has found another subquery with receive node on the same level
                    // Not going to support this kind of subquery join with 2 fragment plan.
                    setJoinValid(false);
                    setJoinInvalidReason("This multipartition query is not plannable.  " + "It has a subquery which cannot be single partition.");
                    // Still needs to count the independent partition tables
                    break;
                }
                subqueryHasReceiveNode = true;
                if (subScan.isTableAggregate()) {
                    // Any process based on this subquery should require 1 fragment only.
                    continue;
                }
            } else {
                // this subquery partition table without receive node
                hasPartitionedTableJoin = true;
            }
        } else {
            // This table is a partition table
            hasPartitionedTableJoin = true;
        }
        boolean unfiltered = true;
        for (AbstractExpression candidateColumn : valueEquivalence.keySet()) {
            if (!(candidateColumn instanceof TupleValueExpression)) {
                continue;
            }
            TupleValueExpression candidatePartitionKey = (TupleValueExpression) candidateColumn;
            if (!canCoverPartitioningColumn(candidatePartitionKey, columnsNeedingCoverage)) {
                continue;
            }
            unfiltered = false;
            if (tokenPartitionKey == null) {
                tokenPartitionKey = candidatePartitionKey;
            }
            eqSets.add(valueEquivalence.get(candidatePartitionKey));
        }
        if (unfiltered) {
            ++unfilteredPartitionKeyCount;
        }
    }
    // end for each table StmtTableScan in the collection
    m_countOfIndependentlyPartitionedTables = eqSets.size() + unfilteredPartitionKeyCount;
    //* enable to debug */ System.out.println("DEBUG: analyze4MPAccess found: " + m_countOfIndependentlyPartitionedTables + " = " + eqSets.size() + " + " + unfilteredPartitionKeyCount);
    if (m_countOfIndependentlyPartitionedTables > 1) {
        setJoinValid(false);
        setJoinInvalidReason("This query is not plannable.  " + "The planner cannot guarantee that all rows would be in a single partition.");
    }
    // on outer level. Not going to support this kind of join.
    if (subqueryHasReceiveNode && hasPartitionedTableJoin) {
        setJoinValid(false);
        setJoinInvalidReason("This query is not plannable.  It has a subquery which needs cross-partition access.");
    }
    if ((unfilteredPartitionKeyCount == 0) && (eqSets.size() == 1)) {
        for (Set<AbstractExpression> partitioningValues : eqSets) {
            for (AbstractExpression constExpr : partitioningValues) {
                if (constExpr instanceof TupleValueExpression) {
                    continue;
                }
                VoltType valueType = tokenPartitionKey.getValueType();
                addPartitioningExpression(tokenPartitionKey.getTableName() + '.' + tokenPartitionKey.getColumnName(), constExpr, valueType);
                // Only need one constant value.
                break;
            }
        }
    }
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractReceivePlanNode(org.voltdb.plannodes.AbstractReceivePlanNode) Set(java.util.Set) HashSet(java.util.HashSet) SchemaColumn(org.voltdb.plannodes.SchemaColumn) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan) AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltType(org.voltdb.VoltType) HashSet(java.util.HashSet)

Example 7 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.

the class SubPlanAssembler method removeNotNullCoveredExpressions.

/**
     * Remove NOT NULL expressions that are covered by the NULL-rejecting expressions. For example,
     * 'COL IS NOT NULL' is covered by the 'COL > 0' NULL-rejecting comparison expression.
     *
     * @param tableScan
     * @param coveringExprs
     * @param exprsToCover
     * @return List<AbstractExpression>
     */
private static List<AbstractExpression> removeNotNullCoveredExpressions(StmtTableScan tableScan, List<AbstractExpression> coveringExprs, List<AbstractExpression> exprsToCover) {
    // Collect all TVEs from NULL-rejecting covering expressions
    Set<TupleValueExpression> coveringTves = new HashSet<>();
    for (AbstractExpression coveringExpr : coveringExprs) {
        if (ExpressionUtil.isNullRejectingExpression(coveringExpr, tableScan.getTableAlias())) {
            coveringTves.addAll(ExpressionUtil.getTupleValueExpressions(coveringExpr));
        }
    }
    // For each NOT NULL expression to cover extract the TVE expressions. If all of them are also part
    // of the covering NULL-rejecting collection then this NOT NULL expression is covered
    Iterator<AbstractExpression> iter = exprsToCover.iterator();
    while (iter.hasNext()) {
        AbstractExpression filter = iter.next();
        if (ExpressionType.OPERATOR_NOT == filter.getExpressionType()) {
            assert (filter.getLeft() != null);
            if (ExpressionType.OPERATOR_IS_NULL == filter.getLeft().getExpressionType()) {
                assert (filter.getLeft().getLeft() != null);
                List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(filter.getLeft().getLeft());
                if (coveringTves.containsAll(tves)) {
                    iter.remove();
                }
            }
        }
    }
    return exprsToCover;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) HashSet(java.util.HashSet)

Example 8 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.

the class JoinNode method getTablesForExpression.

private static void getTablesForExpression(AbstractExpression expr, HashSet<String> tableAliasSet) {
    List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(expr);
    for (TupleValueExpression tupleExpr : tves) {
        String tableAlias = tupleExpr.getTableAlias();
        tableAliasSet.add(tableAlias);
    }
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression)

Example 9 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.

the class TestPlansSubQueries method testParameters.

public void testParameters() {
    AbstractPlanNode pn = compile("select A1 FROM (SELECT A A1 FROM R1 WHERE A > ? LIMIT 10) TEMP WHERE A1 < ?");
    pn = pn.getChild(0);
    assertTrue(pn instanceof SeqScanPlanNode);
    AbstractExpression p = ((SeqScanPlanNode) pn).getPredicate();
    assertTrue(p != null);
    assertTrue(p instanceof ComparisonExpression);
    AbstractExpression cp = p.getLeft();
    assertTrue(cp instanceof TupleValueExpression);
    cp = p.getRight();
    assertTrue(cp instanceof ParameterValueExpression);
    assertEquals(1, ((ParameterValueExpression) cp).getParameterIndex().intValue());
    assertTrue(pn.getChildCount() == 1);
    assertTrue(pn.getChild(0) instanceof SeqScanPlanNode);
    SeqScanPlanNode sc = (SeqScanPlanNode) pn.getChild(0);
    assertTrue(sc.getPredicate() != null);
    p = sc.getPredicate();
    assertTrue(p instanceof ComparisonExpression);
    cp = p.getRight();
    assertTrue(cp instanceof ParameterValueExpression);
    assertEquals(0, ((ParameterValueExpression) cp).getParameterIndex().intValue());
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) ComparisonExpression(org.voltdb.expressions.ComparisonExpression) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression)

Example 10 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression in project voltdb by VoltDB.

the class TestSelfJoins method testSelfJoin.

public void testSelfJoin() {
    AbstractPlanNode pn = compile("select * FROM R1 A JOIN R1 B ON A.C = B.C WHERE B.A > 0 AND A.C < 3");
    pn = pn.getChild(0).getChild(0);
    assertTrue(pn instanceof NestLoopPlanNode);
    assertEquals(4, pn.getOutputSchema().getColumns().size());
    assertEquals(2, pn.getChildCount());
    AbstractPlanNode c = pn.getChild(0);
    assertTrue(c instanceof SeqScanPlanNode);
    SeqScanPlanNode ss = (SeqScanPlanNode) c;
    assertEquals("R1", ss.getTargetTableName());
    assertEquals("A", ss.getTargetTableAlias());
    assertEquals(ExpressionType.COMPARE_LESSTHAN, ss.getPredicate().getExpressionType());
    c = pn.getChild(1);
    assertTrue(c instanceof SeqScanPlanNode);
    ss = (SeqScanPlanNode) c;
    assertEquals("R1", ss.getTargetTableName());
    assertEquals("B", ss.getTargetTableAlias());
    assertEquals(ExpressionType.COMPARE_GREATERTHAN, ss.getPredicate().getExpressionType());
    pn = compile("select * FROM R1 JOIN R1 B ON R1.C = B.C");
    pn = pn.getChild(0).getChild(0);
    assertTrue(pn instanceof NestLoopPlanNode);
    assertEquals(4, pn.getOutputSchema().getColumns().size());
    assertEquals(2, pn.getChildCount());
    c = pn.getChild(0);
    assertTrue(c instanceof SeqScanPlanNode);
    ss = (SeqScanPlanNode) c;
    assertEquals("R1", ss.getTargetTableName());
    assertEquals("R1", ss.getTargetTableAlias());
    c = pn.getChild(1);
    assertTrue(c instanceof SeqScanPlanNode);
    ss = (SeqScanPlanNode) c;
    assertEquals("R1", ss.getTargetTableName());
    assertEquals("B", ss.getTargetTableAlias());
    pn = compile("select A.A, A.C, B.A, B.C FROM R1 A JOIN R1 B ON A.C = B.C");
    pn = pn.getChild(0).getChild(0);
    assertTrue(pn instanceof NestLoopPlanNode);
    assertEquals(4, pn.getOutputSchema().getColumns().size());
    pn = compile("select A,B.C  FROM R1 A JOIN R2 B USING(A)");
    pn = pn.getChild(0);
    assertTrue(pn instanceof ProjectionPlanNode);
    NodeSchema ns = pn.getOutputSchema();
    for (SchemaColumn sc : ns.getColumns()) {
        AbstractExpression e = sc.getExpression();
        assertTrue(e instanceof TupleValueExpression);
        TupleValueExpression tve = (TupleValueExpression) e;
        assertNotSame(-1, tve.getColumnIndex());
    }
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) SchemaColumn(org.voltdb.plannodes.SchemaColumn) NestLoopPlanNode(org.voltdb.plannodes.NestLoopPlanNode) NodeSchema(org.voltdb.plannodes.NodeSchema) ProjectionPlanNode(org.voltdb.plannodes.ProjectionPlanNode)

Aggregations

TupleValueExpression (org.voltdb.expressions.TupleValueExpression)83 AbstractExpression (org.voltdb.expressions.AbstractExpression)59 SchemaColumn (org.voltdb.plannodes.SchemaColumn)19 Column (org.voltdb.catalog.Column)17 ArrayList (java.util.ArrayList)16 HashSet (java.util.HashSet)14 Constraint (org.voltdb.catalog.Constraint)13 Table (org.voltdb.catalog.Table)10 ColumnRef (org.voltdb.catalog.ColumnRef)9 ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)9 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)9 JSONException (org.json_voltpatches.JSONException)8 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)8 NodeSchema (org.voltdb.plannodes.NodeSchema)8 ConstantValueExpression (org.voltdb.expressions.ConstantValueExpression)7 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)6 Set (java.util.Set)5 Index (org.voltdb.catalog.Index)5 StmtTargetTableScan (org.voltdb.planner.parseinfo.StmtTargetTableScan)5 ProjectionPlanNode (org.voltdb.plannodes.ProjectionPlanNode)5