Search in sources :

Example 6 with AbstractExpression

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

use of org.voltdb.expressions.AbstractExpression 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 8 with AbstractExpression

use of org.voltdb.expressions.AbstractExpression 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 9 with AbstractExpression

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

the class AbstractParsedStmt method parseConditionTree.

/**
     * Convert a HSQL VoltXML expression to an AbstractExpression tree.
     * @param root
     * @return configured AbstractExpression
     */
// -- the function is now also called by DDLCompiler with no AbstractParsedStmt in sight --
// so, the methods COULD be relocated to class AbstractExpression or ExpressionUtil.
protected AbstractExpression parseConditionTree(VoltXMLElement root) {
    AbstractExpression expr = parseExpressionNode(root);
    // If there were any IN expressions optionally joined by ANDs and ORs
    // at the top of a condition, it is safe to rewrite them as
    // easier-to-optimize EXISTS expressions.
    // The assumption is that FALSE boolean results can replace NULL
    // boolean results in this context without a change in behavior.
    expr = optimizeInExpressions(expr);
    rejectDisallowedRowOpExpressions(expr);
    // If there were any subquery expressions appearing in a scalar context,
    // we must wrap them in ScalarValueExpressions to avoid wrong answers.
    // See ENG-8226.
    expr = ExpressionUtil.wrapScalarSubqueries(expr);
    return expr;
}
Also used : AbstractExpression(org.voltdb.expressions.AbstractExpression)

Example 10 with AbstractExpression

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

the class AbstractParsedStmt method parseExpressionNode.

/**
     * Given a VoltXMLElement expression node, translate it into an
     * AbstractExpression.  This is mostly a lookup in the table
     * m_exprParsers.
     */
private AbstractExpression parseExpressionNode(VoltXMLElement exprNode) {
    String elementName = exprNode.name.toLowerCase();
    AbstractExpression retval = null;
    XMLElementExpressionParser parser = m_exprParsers.get(elementName);
    if (parser == null) {
        throw new PlanningErrorException("Unsupported expression node '" + elementName + "'");
    }
    retval = parser.parse(this, exprNode);
    assert ("asterisk".equals(elementName) || retval != null);
    return retval;
}
Also used : AbstractExpression(org.voltdb.expressions.AbstractExpression)

Aggregations

AbstractExpression (org.voltdb.expressions.AbstractExpression)215 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)59 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)55 ArrayList (java.util.ArrayList)43 SeqScanPlanNode (org.voltdb.plannodes.SeqScanPlanNode)26 SchemaColumn (org.voltdb.plannodes.SchemaColumn)25 NestLoopPlanNode (org.voltdb.plannodes.NestLoopPlanNode)23 Constraint (org.voltdb.catalog.Constraint)22 IndexScanPlanNode (org.voltdb.plannodes.IndexScanPlanNode)22 HashSet (java.util.HashSet)21 Column (org.voltdb.catalog.Column)21 AbstractScanPlanNode (org.voltdb.plannodes.AbstractScanPlanNode)21 JSONException (org.json_voltpatches.JSONException)19 ColumnRef (org.voltdb.catalog.ColumnRef)19 Table (org.voltdb.catalog.Table)17 AbstractSubqueryExpression (org.voltdb.expressions.AbstractSubqueryExpression)16 ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)16 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)16 ExpressionType (org.voltdb.types.ExpressionType)16 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)14