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;
}
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;
}
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;
}
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;
}
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;
}
Aggregations