use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.
the class ParsedUnionStmt method breakUpSetOpSubquery.
/**
* Break up UNION/INTERSECT (ALL) set ops into individual selects that are part
* of the IN/EXISTS subquery into multiple expressions for each set op child
* combined by the conjunction AND/OR expression.
* col IN ( queryA UNION queryB ) - > col IN (queryA) OR col IN (queryB)
* col IN ( queryA INTERSECTS queryB ) - > col IN (queryA) AND col IN (queryB)
* The EXCEPT set op is LEFT as is
* Also the ALL qualifier is dropped because IN/EXISTS expressions only
* need just one tuple in the results set
*
* @param subqueryExpr - IN/EXISTS expression with a possible SET OP subquery
* @return simplified expression
*/
protected static AbstractExpression breakUpSetOpSubquery(AbstractExpression expr) {
assert (expr != null);
SelectSubqueryExpression subqueryExpr = null;
if (expr.getExpressionType() == ExpressionType.COMPARE_EQUAL && expr.getRight() instanceof SelectSubqueryExpression) {
subqueryExpr = (SelectSubqueryExpression) expr.getRight();
} else if (expr.getExpressionType() == ExpressionType.OPERATOR_EXISTS && expr.getLeft() instanceof SelectSubqueryExpression) {
subqueryExpr = (SelectSubqueryExpression) expr.getLeft();
}
if (subqueryExpr == null) {
return expr;
}
AbstractParsedStmt subquery = subqueryExpr.getSubqueryStmt();
if (!(subquery instanceof ParsedUnionStmt)) {
return expr;
}
ParsedUnionStmt setOpStmt = (ParsedUnionStmt) subquery;
if (UnionType.EXCEPT == setOpStmt.m_unionType || UnionType.EXCEPT_ALL == setOpStmt.m_unionType) {
setOpStmt.m_unionType = UnionType.EXCEPT;
return expr;
}
if (UnionType.UNION_ALL == setOpStmt.m_unionType) {
setOpStmt.m_unionType = UnionType.UNION;
} else if (UnionType.INTERSECT_ALL == setOpStmt.m_unionType) {
setOpStmt.m_unionType = UnionType.INTERSECT;
}
ExpressionType conjuctionType = (setOpStmt.m_unionType == UnionType.UNION) ? ExpressionType.CONJUNCTION_OR : ExpressionType.CONJUNCTION_AND;
AbstractExpression retval = null;
AbstractParsedStmt parentStmt = subquery.m_parentStmt;
// It's a subquery which means it must have a parent
assert (parentStmt != null);
for (AbstractParsedStmt child : setOpStmt.m_children) {
// add table to the query cache
String withoutAlias = null;
StmtSubqueryScan tableCache = parentStmt.addSubqueryToStmtCache(child, withoutAlias);
AbstractExpression childSubqueryExpr = new SelectSubqueryExpression(subqueryExpr.getExpressionType(), tableCache);
AbstractExpression newExpr = null;
try {
newExpr = expr.getExpressionType().getExpressionClass().newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(), e);
}
newExpr.setExpressionType(expr.getExpressionType());
if (ExpressionType.COMPARE_EQUAL == expr.getExpressionType()) {
newExpr.setLeft(expr.getLeft().clone());
newExpr.setRight(childSubqueryExpr);
assert (newExpr instanceof ComparisonExpression);
((ComparisonExpression) newExpr).setQuantifier(((ComparisonExpression) expr).getQuantifier());
} else {
newExpr.setLeft(childSubqueryExpr);
}
// Recurse
newExpr = ParsedUnionStmt.breakUpSetOpSubquery(newExpr);
if (retval == null) {
retval = newExpr;
} else {
retval = new ConjunctionExpression(conjuctionType, retval, newExpr);
}
}
return retval;
}
use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.
the class IndexScanPlanNode method buildSkipNullPredicate.
public static AbstractExpression buildSkipNullPredicate(int nullExprIndex, Index catalogIndex, StmtTableScan tableScan, List<AbstractExpression> searchkeyExpressions, List<Boolean> compareNotDistinct) {
String exprsjson = catalogIndex.getExpressionsjson();
List<AbstractExpression> indexedExprs = null;
if (exprsjson.isEmpty()) {
indexedExprs = new ArrayList<>();
List<ColumnRef> indexedColRefs = CatalogUtil.getSortedCatalogItems(catalogIndex.getColumns(), "index");
assert (nullExprIndex < indexedColRefs.size());
for (int i = 0; i <= nullExprIndex; i++) {
ColumnRef colRef = indexedColRefs.get(i);
Column col = colRef.getColumn();
TupleValueExpression tve = new TupleValueExpression(tableScan.getTableName(), tableScan.getTableAlias(), col, col.getIndex());
indexedExprs.add(tve);
}
} else {
try {
indexedExprs = AbstractExpression.fromJSONArrayString(exprsjson, tableScan);
assert (nullExprIndex < indexedExprs.size());
} catch (JSONException e) {
e.printStackTrace();
assert (false);
}
}
// For a partial index extract all TVE expressions from it predicate if it's NULL-rejecting expression
// These TVEs do not need to be added to the skipNUll predicate because it's redundant.
AbstractExpression indexPredicate = null;
Set<TupleValueExpression> notNullTves = null;
String indexPredicateJson = catalogIndex.getPredicatejson();
if (!StringUtil.isEmpty(indexPredicateJson)) {
try {
indexPredicate = AbstractExpression.fromJSONString(indexPredicateJson, tableScan);
assert (indexPredicate != null);
} catch (JSONException e) {
e.printStackTrace();
assert (false);
}
if (ExpressionUtil.isNullRejectingExpression(indexPredicate, tableScan.getTableAlias())) {
notNullTves = new HashSet<>();
notNullTves.addAll(ExpressionUtil.getTupleValueExpressions(indexPredicate));
}
}
AbstractExpression nullExpr = indexedExprs.get(nullExprIndex);
AbstractExpression skipNullPredicate = null;
if (notNullTves == null || !notNullTves.contains(nullExpr)) {
List<AbstractExpression> exprs = new ArrayList<>();
for (int i = 0; i < nullExprIndex; i++) {
AbstractExpression idxExpr = indexedExprs.get(i);
ExpressionType exprType = ExpressionType.COMPARE_EQUAL;
if (i < compareNotDistinct.size() && compareNotDistinct.get(i)) {
exprType = ExpressionType.COMPARE_NOTDISTINCT;
}
AbstractExpression expr = new ComparisonExpression(exprType, idxExpr, searchkeyExpressions.get(i).clone());
exprs.add(expr);
}
// then we add "nullExpr IS NULL" to the expression for matching tuples to skip. (ENG-11096)
if (nullExprIndex == searchkeyExpressions.size() || compareNotDistinct.get(nullExprIndex) == false) {
// nullExprIndex == m_searchkeyExpressions.size() - 1
AbstractExpression expr = new OperatorExpression(ExpressionType.OPERATOR_IS_NULL, nullExpr, null);
exprs.add(expr);
} else {
return null;
}
skipNullPredicate = ExpressionUtil.combinePredicates(exprs);
skipNullPredicate.finalizeValueTypes();
}
return skipNullPredicate;
}
use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.
the class SubPlanAssembler method replaceInListFilterWithEqualityFilter.
// Replace the IN LIST condition in the end expression referencing the first given rhs
// with an equality filter referencing the second given rhs.
private static void replaceInListFilterWithEqualityFilter(List<AbstractExpression> endExprs, AbstractExpression inListRhs, AbstractExpression equalityRhs) {
for (AbstractExpression comparator : endExprs) {
AbstractExpression otherExpr = comparator.getRight();
if (otherExpr == inListRhs) {
endExprs.remove(comparator);
AbstractExpression replacement = new ComparisonExpression(ExpressionType.COMPARE_EQUAL, comparator.getLeft(), equalityRhs);
endExprs.add(replacement);
break;
}
}
}
use of org.voltdb.expressions.ComparisonExpression 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.expressions.ComparisonExpression 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