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