Search in sources :

Example 1 with TupleValueExpression

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

the class AbstractParsedStmt method replaceExpressionsWithPve.

/**
     * Helper method to replace all TVEs and aggregated expressions with the corresponding PVEs.
     * The original expressions are placed into the map to be propagated to the EE.
     * The key to the map is the parameter index.
     *
     *
     * @param stmt - subquery statement
     * @param expr - expression with parent TVEs
     * @return Expression with parent TVE replaced with PVE
     */
protected AbstractExpression replaceExpressionsWithPve(AbstractExpression expr) {
    assert (expr != null);
    if (expr instanceof TupleValueExpression) {
        int paramIdx = NEXT_PARAMETER_ID++;
        ParameterValueExpression pve = new ParameterValueExpression(paramIdx, expr);
        m_parameterTveMap.put(paramIdx, expr);
        return pve;
    }
    if (expr instanceof AggregateExpression) {
        int paramIdx = NEXT_PARAMETER_ID++;
        ParameterValueExpression pve = new ParameterValueExpression(paramIdx, expr);
        // Disallow aggregation of parent columns in a subquery.
        // except the case HAVING AGG(T1.C1) IN (SELECT T2.C2 ...)
        List<TupleValueExpression> tves = ExpressionUtil.getTupleValueExpressions(expr);
        assert (m_parentStmt != null);
        for (TupleValueExpression tve : tves) {
            int origId = tve.getOrigStmtId();
            if (m_stmtId != origId && m_parentStmt.m_stmtId != origId) {
                throw new PlanningErrorException("Subqueries do not support aggregation of parent statement columns");
            }
        }
        m_parameterTveMap.put(paramIdx, expr);
        return pve;
    }
    if (expr.getLeft() != null) {
        expr.setLeft(replaceExpressionsWithPve(expr.getLeft()));
    }
    if (expr.getRight() != null) {
        expr.setRight(replaceExpressionsWithPve(expr.getRight()));
    }
    if (expr.getArgs() != null) {
        List<AbstractExpression> newArgs = new ArrayList<>();
        for (AbstractExpression argument : expr.getArgs()) {
            newArgs.add(replaceExpressionsWithPve(argument));
        }
        expr.setArgs(newArgs);
    }
    return expr;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ArrayList(java.util.ArrayList) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) AggregateExpression(org.voltdb.expressions.AggregateExpression) Constraint(org.voltdb.catalog.Constraint)

Example 2 with TupleValueExpression

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

the class AbstractParsedStmt method parseColumnRefExpression.

/**
     *
     * @param exprNode
     * @return
     */
private AbstractExpression parseColumnRefExpression(VoltXMLElement exprNode) {
    String tableName = exprNode.attributes.get("table");
    if (tableName == null) {
        assert (m_DDLIndexedTable != null);
        tableName = m_DDLIndexedTable.getTypeName();
    }
    assert (tableName != null);
    String tableAlias = exprNode.attributes.get("tablealias");
    if (tableAlias == null) {
        tableAlias = tableName;
    }
    String columnName = exprNode.attributes.get("column");
    String columnAlias = exprNode.attributes.get("alias");
    // Whether or not this column is the coalesced column produced by a join with a
    // USING predicate.
    String usingAttr = exprNode.attributes.get("using");
    boolean isUsingColumn = usingAttr != null ? Boolean.parseBoolean(usingAttr) : false;
    // Use the index produced by HSQL as a way to differentiate columns that have
    // the same name with a single table (which can happen for subqueries containing joins).
    int differentiator = Integer.parseInt(exprNode.attributes.get("index"));
    if (differentiator == -1 && isUsingColumn) {
        for (VoltXMLElement usingElem : exprNode.children) {
            String usingTableAlias = usingElem.attributes.get("tablealias");
            if (usingTableAlias != null && usingTableAlias.equals(tableAlias)) {
                differentiator = Integer.parseInt(usingElem.attributes.get("index"));
            }
        }
    }
    TupleValueExpression tve = new TupleValueExpression(tableName, tableAlias, columnName, columnAlias, -1, differentiator);
    // Collect the unique columns used in the plan for a given scan.
    // Resolve the tve and add it to the scan's cache of referenced columns
    // Get tableScan where this TVE is originated from. In case of the
    // correlated queries it may not be THIS statement but its parent
    StmtTableScan tableScan = resolveStmtTableScanByAlias(tableAlias);
    if (tableScan == null) {
        // from TestVoltCompler.testScalarSubqueriesExpectedFailures.
        throw new PlanningErrorException("Object not found: " + tableAlias);
    }
    AbstractExpression resolvedExpr = tableScan.resolveTVE(tve);
    if (m_stmtId == tableScan.getStatementId()) {
        return resolvedExpr;
    }
    // This is a TVE from the correlated expression
    int paramIdx = NEXT_PARAMETER_ID++;
    ParameterValueExpression pve = new ParameterValueExpression(paramIdx, resolvedExpr);
    m_parameterTveMap.put(paramIdx, resolvedExpr);
    return pve;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) Constraint(org.voltdb.catalog.Constraint) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan)

Example 3 with TupleValueExpression

use of org.voltdb.expressions.TupleValueExpression 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 4 with TupleValueExpression

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

the class AbstractParsedStmt method parseWindowedAggregationExpression.

/**
     * Parse a windowed expression.  This actually just returns a TVE.  The
     * WindowFunctionExpression is squirreled away in the m_windowFunctionExpressions
     * object, though, because we will need it later.
     *
     * @param exprNode
     * @return
     */
private AbstractExpression parseWindowedAggregationExpression(VoltXMLElement exprNode) {
    int id = Integer.parseInt(exprNode.attributes.get("id"));
    String optypeName = exprNode.attributes.get("optype");
    ExpressionType optype = ExpressionType.get(optypeName);
    if (optype == ExpressionType.INVALID) {
        throw new PlanningErrorException("Undefined windowed function call " + optypeName);
    }
    // the windowed expression, then this is an error.
    if (!m_parsingInDisplayColumns) {
        if (m_windowFunctionExpressions.size() > 0) {
            WindowFunctionExpression we = m_windowFunctionExpressions.get(0);
            if (we.getXMLID() == id) {
                // away in the windowed expression.
                return we.getDisplayListExpression();
            }
        }
        throw new PlanningErrorException("Windowed function call expressions can only appear in the selection list of a query or subquery.");
    }
    // Parse individual aggregate expressions
    List<AbstractExpression> partitionbyExprs = new ArrayList<>();
    List<AbstractExpression> orderbyExprs = new ArrayList<>();
    List<SortDirectionType> orderbyDirs = new ArrayList<>();
    List<AbstractExpression> aggParams = new ArrayList<>();
    for (VoltXMLElement childEle : exprNode.children) {
        if (childEle.name.equals("winspec")) {
            for (VoltXMLElement ele : childEle.children) {
                if (ele.name.equals("partitionbyList")) {
                    for (VoltXMLElement childNode : ele.children) {
                        AbstractExpression expr = parseExpressionNode(childNode);
                        ExpressionUtil.finalizeValueTypes(expr);
                        partitionbyExprs.add(expr);
                    }
                } else if (ele.name.equals("orderbyList")) {
                    for (VoltXMLElement childNode : ele.children) {
                        SortDirectionType sortDir = Boolean.valueOf(childNode.attributes.get("descending")) ? SortDirectionType.DESC : SortDirectionType.ASC;
                        AbstractExpression expr = parseExpressionNode(childNode.children.get(0));
                        ExpressionUtil.finalizeValueTypes(expr);
                        orderbyExprs.add(expr);
                        orderbyDirs.add(sortDir);
                    }
                }
            }
        } else {
            AbstractExpression aggParam = parseExpressionNode(childEle);
            if (aggParam != null) {
                aggParam.finalizeValueTypes();
                aggParams.add(aggParam);
            }
        }
    }
    String alias = WINDOWED_AGGREGATE_COLUMN_NAME;
    if (exprNode.attributes.containsKey("alias")) {
        alias = exprNode.attributes.get("alias");
    }
    WindowFunctionExpression rankExpr = new WindowFunctionExpression(optype, partitionbyExprs, orderbyExprs, orderbyDirs, aggParams, id);
    ExpressionUtil.finalizeValueTypes(rankExpr);
    // Only offset 0 is useful.  But we keep the index anyway.
    int offset = m_windowFunctionExpressions.size();
    m_windowFunctionExpressions.add(rankExpr);
    TupleValueExpression tve = new TupleValueExpression(TEMP_TABLE_NAME, TEMP_TABLE_NAME, alias, alias, rankExpr, offset);
    // This tve does not ever need a differentiator.
    tve.setNeedsNoDifferentiation();
    rankExpr.setDisplayListExpression(tve);
    return tve;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) WindowFunctionExpression(org.voltdb.expressions.WindowFunctionExpression) ArrayList(java.util.ArrayList) SortDirectionType(org.voltdb.types.SortDirectionType) VoltXMLElement(org.hsqldb_voltpatches.VoltXMLElement) ExpressionType(org.voltdb.types.ExpressionType) Constraint(org.voltdb.catalog.Constraint)

Example 5 with TupleValueExpression

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

the class JoinNode method applyTransitiveEquivalence.

private static List<AbstractExpression> applyTransitiveEquivalence(List<AbstractExpression> singleTableExprs, List<AbstractExpression> twoTableExprs) {
    ArrayList<AbstractExpression> simplifiedExprs = new ArrayList<>();
    HashMap<AbstractExpression, Set<AbstractExpression>> eqMap1 = new HashMap<>();
    ExpressionUtil.collectPartitioningFilters(singleTableExprs, eqMap1);
    for (AbstractExpression expr : twoTableExprs) {
        if (!expr.isColumnEquivalenceFilter()) {
            continue;
        }
        AbstractExpression leftExpr = expr.getLeft();
        AbstractExpression rightExpr = expr.getRight();
        assert (leftExpr instanceof TupleValueExpression && rightExpr instanceof TupleValueExpression);
        Set<AbstractExpression> eqSet1 = eqMap1.get(leftExpr);
        AbstractExpression singleExpr = leftExpr;
        if (eqSet1 == null) {
            eqSet1 = eqMap1.get(rightExpr);
            if (eqSet1 == null) {
                continue;
            }
            singleExpr = rightExpr;
        }
        for (AbstractExpression eqExpr : eqSet1) {
            if (eqExpr instanceof ConstantValueExpression) {
                if (singleExpr == leftExpr) {
                    expr.setLeft(eqExpr);
                } else {
                    expr.setRight(eqExpr);
                }
                simplifiedExprs.add(expr);
                // much sense, right?
                break;
            }
        }
    }
    twoTableExprs.removeAll(simplifiedExprs);
    return simplifiedExprs;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Set(java.util.Set) HashSet(java.util.HashSet) AbstractExpression(org.voltdb.expressions.AbstractExpression) HashMap(java.util.HashMap) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ArrayList(java.util.ArrayList)

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