use of org.voltdb.types.ExpressionType in project voltdb by VoltDB.
the class ParsedSelectStmt method verifyWindowFunctionExpressions.
/**
* Verify the validity of the windowed expressions.
*
* @return
*/
private void verifyWindowFunctionExpressions() {
// Check for windowed expressions.
if (m_windowFunctionExpressions.size() > 0) {
if (m_windowFunctionExpressions.size() > 1) {
throw new PlanningErrorException("Only one windowed function call may appear in a selection list.");
}
if (m_hasAggregateExpression) {
throw new PlanningErrorException("Use of window functions (in an OVER clause) isn't supported with other aggregate functions on the SELECT list.");
}
if (m_windowFunctionExpressions.get(0).hasSubqueryArgs()) {
throw new PlanningErrorException("Window function calls with subquery expression arguments are not allowed.");
}
//
// This could be an if statement, but I think it's better to
// leave this as a pattern in case we decide to implement more
// legality conditions for other windowed operators.
//
WindowFunctionExpression windowFunctionExpression = m_windowFunctionExpressions.get(0);
List<AbstractExpression> orderByExpressions = windowFunctionExpression.getOrderByExpressions();
ExpressionType exprType = windowFunctionExpression.getExpressionType();
String aggName = exprType.symbol().toUpperCase();
switch(exprType) {
case AGGREGATE_WINDOWED_RANK:
case AGGREGATE_WINDOWED_DENSE_RANK:
if (orderByExpressions.size() == 0) {
throw new PlanningErrorException("Windowed " + aggName + " function call expressions require an ORDER BY specification.");
}
VoltType valType = orderByExpressions.get(0).getValueType();
assert (valType != null);
if (!valType.isAnyIntegerType() && (valType != VoltType.TIMESTAMP)) {
throw new PlanningErrorException("Windowed function call expressions can have only integer or TIMESTAMP value types in the ORDER BY expression of their window.");
}
break;
case AGGREGATE_WINDOWED_COUNT:
if (windowFunctionExpression.getAggregateArguments().size() > 1) {
throw new PlanningErrorException(String.format("Windowed COUNT must have either exactly one argument or else a star for an argument"));
}
// Any type is ok, so we won't inspect the type.
break;
case AGGREGATE_WINDOWED_MAX:
case AGGREGATE_WINDOWED_MIN:
if (windowFunctionExpression.getAggregateArguments().size() != 1) {
throw new PlanningErrorException(String.format("Windowed %s must have exactly one argument", aggName));
}
// Any type is ok, so we won't inspect the type.
break;
case AGGREGATE_WINDOWED_SUM:
if (windowFunctionExpression.getAggregateArguments().size() != 1) {
throw new PlanningErrorException(String.format("Windowed SUM must have exactly one numeric argument"));
}
AbstractExpression arg = windowFunctionExpression.getAggregateArguments().get(0);
VoltType vt = arg.getValueType();
assert (vt != null);
if (!vt.isNumber()) {
throw new PlanningErrorException("Windowed SUM must have exactly one numeric argument");
}
break;
default:
{
String opName = (exprType == null) ? "NULL" : exprType.symbol();
throw new PlanningErrorException("Unknown windowed aggregate function type: " + opName);
}
}
}
}
use of org.voltdb.types.ExpressionType in project voltdb by VoltDB.
the class AggregatePlanNode method explainPlanForNode.
@Override
protected String explainPlanForNode(String indent) {
StringBuilder sb = new StringBuilder();
String optionalTableName = "*NO MATCH -- USE ALL TABLE NAMES*";
String aggType = planNodeTypeToAggDescString(getPlanNodeType());
sb.append(aggType + " AGGREGATION ops: ");
String sep = "";
int ii = 0;
for (ExpressionType e : m_aggregateTypes) {
sb.append(sep).append(e.symbol());
sep = ", ";
if (e != ExpressionType.AGGREGATE_COUNT_STAR) {
if (m_aggregateDistinct.get(ii) == 1) {
sb.append(" DISTINCT");
}
AbstractExpression ae = m_aggregateExpressions.get(ii);
assert (ae != null);
sb.append("(");
sb.append(ae.explain(optionalTableName));
sb.append(")");
}
++ii;
}
if (m_prePredicate != null) {
sb.append(" ONLY IF " + m_prePredicate.explain(optionalTableName));
}
if (m_postPredicate != null) {
// HAVING is always defined WRT to the current outputSchema (NOT inputschema).
// This might be a little surprising to the user
// -- maybe we can find some better way to describe the TVEs, here.
sb.append(" HAVING " + m_postPredicate.explain(AbstractParsedStmt.TEMP_TABLE_NAME));
}
return sb.toString();
}
use of org.voltdb.types.ExpressionType in project voltdb by VoltDB.
the class AbstractParsedStmt method parseAggregationExpression.
/**
*
* @param paramsById
* @param exprNode
* @return
*/
private AbstractExpression parseAggregationExpression(VoltXMLElement exprNode) {
String type = exprNode.attributes.get("optype");
ExpressionType exprType = ExpressionType.get(type);
if (exprType == ExpressionType.INVALID) {
throw new PlanningErrorException("Unsupported aggregation type '" + type + "'");
}
assert (exprNode.children.size() <= 1);
// get the single required child node
VoltXMLElement childExprNode = exprNode.children.get(0);
assert (childExprNode != null);
// recursively parse the child subtree -- could (in theory) be an operator or
// a constant, column, or param value operand or null in the specific case of "COUNT(*)".
AbstractExpression childExpr = parseExpressionNode(childExprNode);
if (childExpr == null) {
assert (exprType == ExpressionType.AGGREGATE_COUNT);
exprType = ExpressionType.AGGREGATE_COUNT_STAR;
}
AggregateExpression expr = new AggregateExpression(exprType);
expr.setLeft(childExpr);
String node;
if ((node = exprNode.attributes.get("distinct")) != null && Boolean.parseBoolean(node)) {
expr.setDistinct();
}
if (m_aggregationList != null) {
ExpressionUtil.finalizeValueTypes(expr);
m_aggregationList.add(expr);
}
return expr;
}
use of org.voltdb.types.ExpressionType in project voltdb by VoltDB.
the class AbstractParsedStmt method optimizeInExpressions.
/**
* Perform various optimizations for IN/EXISTS subqueries if possible
*
* @param expr to optimize
* @return optimized expression
*/
private AbstractExpression optimizeInExpressions(AbstractExpression expr) {
ExpressionType exprType = expr.getExpressionType();
if (ExpressionType.CONJUNCTION_AND == exprType || ExpressionType.CONJUNCTION_OR == exprType) {
AbstractExpression optimizedLeft = optimizeInExpressions(expr.getLeft());
expr.setLeft(optimizedLeft);
AbstractExpression optimizedRight = optimizeInExpressions(expr.getRight());
expr.setRight(optimizedRight);
return expr;
}
if (ExpressionType.COMPARE_EQUAL != exprType) {
return expr;
}
assert (expr instanceof ComparisonExpression);
if (((ComparisonExpression) expr).getQuantifier() != QuantifierType.ANY) {
return expr;
}
/*
* Verify that an IN expression can be safely converted to an EXISTS one
* IN (SELECT" forms e.g. "(A, B) IN (SELECT X, Y, FROM ...) =>
* EXISTS (SELECT 42 FROM ... AND|WHERE|HAVING A=X AND|WHERE|HAVING B=Y)
*/
AbstractExpression inColumns = expr.getLeft();
if (inColumns instanceof SelectSubqueryExpression) {
// (expression must return a single row at most)
return expr;
}
// The right hand operand of the equality operation must be a SELECT statement
AbstractExpression rightExpr = expr.getRight();
if (!(rightExpr instanceof SelectSubqueryExpression)) {
return expr;
}
SelectSubqueryExpression subqueryExpr = (SelectSubqueryExpression) rightExpr;
AbstractParsedStmt subquery = subqueryExpr.getSubqueryStmt();
if (!(subquery instanceof ParsedSelectStmt)) {
return expr;
}
ParsedSelectStmt selectStmt = (ParsedSelectStmt) subquery;
// seems to require 1 match that has exactly 10-14 rows (matching or not) with lesser or equal values of Y.
if (selectStmt.hasLimitOrOffset()) {
return expr;
}
ParsedSelectStmt.rewriteInSubqueryAsExists(selectStmt, inColumns);
subqueryExpr.resolveCorrelations();
AbstractExpression existsExpr = new OperatorExpression();
existsExpr.setExpressionType(ExpressionType.OPERATOR_EXISTS);
existsExpr.setLeft(subqueryExpr);
return optimizeExistsExpression(existsExpr);
}
use of org.voltdb.types.ExpressionType in project voltdb by VoltDB.
the class AbstractParsedStmt method parseOperationExpression.
/**
*
* @param paramsById
* @param exprNode
* @return
*/
private AbstractExpression parseOperationExpression(VoltXMLElement exprNode) {
String optype = exprNode.attributes.get("optype");
ExpressionType exprType = ExpressionType.get(optype);
AbstractExpression expr = null;
if (exprType == ExpressionType.INVALID) {
throw new PlanningErrorException("Unsupported operation type '" + optype + "'");
}
try {
expr = exprType.getExpressionClass().newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
expr.setExpressionType(exprType);
if (exprType == ExpressionType.OPERATOR_CASE_WHEN || exprType == ExpressionType.OPERATOR_ALTERNATIVE) {
String valueType = exprNode.attributes.get("valuetype");
expr.setValueType(VoltType.typeFromString(valueType));
}
if (expr instanceof ComparisonExpression) {
String opsubtype = exprNode.attributes.get("opsubtype");
if (opsubtype != null) {
QuantifierType quantifier = QuantifierType.get(opsubtype);
if (quantifier != QuantifierType.NONE) {
((ComparisonExpression) expr).setQuantifier(quantifier);
}
}
}
// get the first (left) node that is an element
VoltXMLElement leftExprNode = exprNode.children.get(0);
assert (leftExprNode != null);
// recursively parse the left subtree (could be another operator or
// a constant/tuple/param value operand).
AbstractExpression leftExpr = parseExpressionNode(leftExprNode);
assert ((leftExpr != null) || (exprType == ExpressionType.AGGREGATE_COUNT));
expr.setLeft(leftExpr);
// get the second (right) node that is an element (might be null)
VoltXMLElement rightExprNode = null;
if (exprNode.children.size() > 1) {
rightExprNode = exprNode.children.get(1);
}
if (expr.needsRightExpression()) {
assert (rightExprNode != null);
// recursively parse the right subtree
AbstractExpression rightExpr = parseExpressionNode(rightExprNode);
assert (rightExpr != null);
expr.setRight(rightExpr);
} else {
assert (rightExprNode == null);
if (exprType == ExpressionType.OPERATOR_CAST) {
String valuetype = exprNode.attributes.get("valuetype");
assert (valuetype != null);
VoltType voltType = VoltType.typeFromString(valuetype);
expr.setValueType(voltType);
// We don't support parameterized casting, such as specifically to "VARCHAR(3)" vs. VARCHAR,
// so assume max length for variable-length types (VARCHAR and VARBINARY).
int size = voltType.getMaxLengthInBytes();
expr.setValueSize(size);
}
}
if (exprType == ExpressionType.COMPARE_EQUAL && QuantifierType.ANY == ((ComparisonExpression) expr).getQuantifier()) {
// Break up UNION/INTERSECT (ALL) set ops into individual selects connected by
// AND/OR operator
// col IN ( queryA UNION queryB ) - > col IN (queryA) OR col IN (queryB)
// col IN ( queryA INTERSECTS queryB ) - > col IN (queryA) AND col IN (queryB)
expr = ParsedUnionStmt.breakUpSetOpSubquery(expr);
} else if (exprType == ExpressionType.OPERATOR_EXISTS) {
expr = optimizeExistsExpression(expr);
}
return expr;
}
Aggregations