Search in sources :

Example 1 with SchemaColumn

use of org.voltdb.plannodes.SchemaColumn in project voltdb by VoltDB.

the class TupleValueExpression method setColumnIndexUsingSchema.

/**
     * Given an input schema, resolve this TVE expression.
     */
public int setColumnIndexUsingSchema(NodeSchema inputSchema) {
    int index = inputSchema.getIndexOfTve(this);
    if (index < 0) {
        //* enable to debug*/ System.out.println("DEBUG: setColumnIndex candidates: " + inputSchema);
        return index;
    }
    setColumnIndex(index);
    if (getValueType() == null) {
        // In case of sub-queries the TVE may not have its
        // value type and size resolved yet. Try to resolve it now
        SchemaColumn inputColumn = inputSchema.getColumns().get(index);
        setTypeSizeAndInBytes(inputColumn);
    }
    return index;
}
Also used : SchemaColumn(org.voltdb.plannodes.SchemaColumn)

Example 2 with SchemaColumn

use of org.voltdb.plannodes.SchemaColumn in project voltdb by VoltDB.

the class InsertSubPlanAssembler method nextPlan.

@Override
AbstractPlanNode nextPlan() {
    if (m_bestAndOnlyPlanWasGenerated) {
        return null;
    }
    // We may generate a few different plans for the subquery, but by the time
    // we get here, we'll generate only one plan for the INSERT statement itself.
    // Mostly this method exists to check that we can find a valid partitioning
    // for the statement.
    m_bestAndOnlyPlanWasGenerated = true;
    ParsedInsertStmt insertStmt = (ParsedInsertStmt) m_parsedStmt;
    Table targetTable = insertStmt.m_tableList.get(0);
    targetTable.getTypeName();
    StmtSubqueryScan subquery = insertStmt.getSubqueryScan();
    boolean subqueryIsMultiFragment = subquery.getBestCostPlan().rootPlanGraph.hasAnyNodeOfType(PlanNodeType.SEND);
    if (targetTable.getIsreplicated()) {
        // setUpForNewPlans already validates this
        assert (!m_partitioning.wasSpecifiedAsSingle() && !m_partitioning.isInferredSingle());
        // Cannot access any partitioned tables in subquery for replicated table
        if (!subquery.getIsReplicated()) {
            throw new PlanningErrorException("Subquery in " + getSqlType() + " INTO ... SELECT statement may not access " + "partitioned data for insertion into replicated table " + targetTable.getTypeName() + ".");
        }
    } else if (!m_partitioning.wasSpecifiedAsSingle()) {
        if (subqueryIsMultiFragment) {
            // What is the appropriate level of detail for this message?
            m_recentErrorMsg = getSqlType() + " INTO ... SELECT statement subquery is too complex.  " + "Please either simplify the subquery or use a SELECT followed by an INSERT.";
            return null;
        }
        Column partitioningCol = targetTable.getPartitioncolumn();
        if (partitioningCol == null) {
            assert (m_targetIsExportTable);
            m_recentErrorMsg = "The target table for an INSERT INTO ... SELECT statement is an " + "stream with no partitioning column defined.  " + "This is not currently supported.  Please define a " + "partitioning column for this stream to use it with INSERT INTO ... SELECT.";
            return null;
        }
        List<StmtTableScan> tables = new ArrayList<>();
        StmtTargetTableScan stmtTargetTableScan = new StmtTargetTableScan(targetTable);
        tables.add(stmtTargetTableScan);
        tables.add(subquery);
        // Create value equivalence between the partitioning column of the target table
        // and the corresponding expression produced by the subquery.
        HashMap<AbstractExpression, Set<AbstractExpression>> valueEquivalence = new HashMap<>();
        int i = 0;
        boolean setEquivalenceForPartitioningCol = false;
        for (Column col : insertStmt.m_columns.keySet()) {
            if (partitioningCol.compareTo(col) == 0) {
                List<SchemaColumn> partitioningColumns = stmtTargetTableScan.getPartitioningColumns();
                assert (partitioningColumns.size() == 1);
                AbstractExpression targetPartitionColExpr = partitioningColumns.get(0).getExpression();
                TupleValueExpression selectedExpr = subquery.getOutputExpression(i);
                assert (!valueEquivalence.containsKey(targetPartitionColExpr));
                assert (!valueEquivalence.containsKey(selectedExpr));
                Set<AbstractExpression> equivSet = new HashSet<>();
                equivSet.add(targetPartitionColExpr);
                equivSet.add(selectedExpr);
                valueEquivalence.put(targetPartitionColExpr, equivSet);
                valueEquivalence.put(selectedExpr, equivSet);
                setEquivalenceForPartitioningCol = true;
            }
            ++i;
        }
        if (!setEquivalenceForPartitioningCol) {
            // partitioning column of target table is not being set from value produced by the subquery.
            m_recentErrorMsg = "Partitioning column must be assigned a value " + "produced by the subquery in an " + getSqlType() + " INTO ... SELECT statement.";
            return null;
        }
        m_partitioning.analyzeForMultiPartitionAccess(tables, valueEquivalence);
        if (!m_partitioning.isJoinValid()) {
            m_recentErrorMsg = "Partitioning could not be determined for " + getSqlType() + " INTO ... SELECT statement.  " + "Please ensure that statement does not attempt to copy row data from one partition to another, " + "which is unsupported.";
            return null;
        }
    }
    return subquery.getBestCostPlan().rootPlanGraph;
}
Also used : StmtSubqueryScan(org.voltdb.planner.parseinfo.StmtSubqueryScan) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Table(org.voltdb.catalog.Table) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) AbstractExpression(org.voltdb.expressions.AbstractExpression) Column(org.voltdb.catalog.Column) SchemaColumn(org.voltdb.plannodes.SchemaColumn) StmtTargetTableScan(org.voltdb.planner.parseinfo.StmtTargetTableScan) ArrayList(java.util.ArrayList) List(java.util.List)

Example 3 with SchemaColumn

use of org.voltdb.plannodes.SchemaColumn 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 4 with SchemaColumn

use of org.voltdb.plannodes.SchemaColumn in project voltdb by VoltDB.

the class StatementPartitioning method canCoverPartitioningColumn.

private static boolean canCoverPartitioningColumn(TupleValueExpression candidatePartitionKey, List<SchemaColumn> columnsNeedingCoverage) {
    if (columnsNeedingCoverage == null)
        return false;
    for (SchemaColumn col : columnsNeedingCoverage) {
        String partitionedTableAlias = col.getTableAlias();
        String columnNeedingCoverage = col.getColumnAlias();
        assert (candidatePartitionKey.getTableAlias() != null);
        if (!candidatePartitionKey.getTableAlias().equals(partitionedTableAlias)) {
            continue;
        }
        String candidateColumnName = candidatePartitionKey.getColumnName();
        if (!candidateColumnName.equals(columnNeedingCoverage)) {
            continue;
        }
        // Maybe need more checkings
        return true;
    }
    return false;
}
Also used : SchemaColumn(org.voltdb.plannodes.SchemaColumn)

Example 5 with SchemaColumn

use of org.voltdb.plannodes.SchemaColumn 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

SchemaColumn (org.voltdb.plannodes.SchemaColumn)37 AbstractExpression (org.voltdb.expressions.AbstractExpression)19 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)16 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)13 NodeSchema (org.voltdb.plannodes.NodeSchema)13 ProjectionPlanNode (org.voltdb.plannodes.ProjectionPlanNode)6 HashSet (java.util.HashSet)5 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)5 AbstractScanPlanNode (org.voltdb.plannodes.AbstractScanPlanNode)5 NestLoopPlanNode (org.voltdb.plannodes.NestLoopPlanNode)5 Table (org.voltdb.catalog.Table)4 OrderByPlanNode (org.voltdb.plannodes.OrderByPlanNode)4 SeqScanPlanNode (org.voltdb.plannodes.SeqScanPlanNode)4 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 Column (org.voltdb.catalog.Column)3 Constraint (org.voltdb.catalog.Constraint)3 AbstractReceivePlanNode (org.voltdb.plannodes.AbstractReceivePlanNode)3 SendPlanNode (org.voltdb.plannodes.SendPlanNode)3 Set (java.util.Set)2