use of org.voltdb.expressions.VectorValueExpression in project voltdb by VoltDB.
the class AbstractParsedStmt method parseVectorExpression.
/**
* Parse a Vector value for SQL-IN
*/
private AbstractExpression parseVectorExpression(VoltXMLElement exprNode) {
ArrayList<AbstractExpression> args = new ArrayList<>();
for (VoltXMLElement argNode : exprNode.children) {
assert (argNode != null);
// recursively parse each argument subtree (could be any kind of expression).
AbstractExpression argExpr = parseExpressionNode(argNode);
assert (argExpr != null);
args.add(argExpr);
}
VectorValueExpression vve = new VectorValueExpression();
vve.setValueType(VoltType.VOLTTABLE);
vve.setArgs(args);
return vve;
}
use of org.voltdb.expressions.VectorValueExpression in project voltdb by VoltDB.
the class SubPlanAssembler method getIndexableExpressionFromFilters.
/**
* For a given filter expression, return a normalized version of it that is always a comparison operator whose
* left-hand-side references the table specified and whose right-hand-side does not.
* Returns null if no such formulation of the filter expression is possible.
* For example, "WHERE F_ID = 2" would return it input intact if F_ID is in the table passed in.
* For join expressions like, "WHERE F_ID = Q_ID", it would also return the input expression if F_ID is in the table
* but Q_ID is not. If only Q_ID were defined for the table, it would return an expression for (Q_ID = F_ID).
* If both Q_ID and F_ID were defined on the table, null would be returned.
* Ideally, the left-hand-side expression is intended to be an indexed expression on the table using the current
* index. To help reduce false positives, the (base) columns and/or indexed expressions of the index are also
* provided to help further reduce non-null returns in uninteresting cases.
*
* @param targetComparator An allowed comparison operator
* -- its reverse is allowed in reversed expressions
* @param altTargetComparator An alternatively allowed comparison operator
* -- its reverse is allowed in reversed expressions
* @param coveringExpr The indexed expression on the table's column
* that might match a query filter, possibly null.
* @param coveringColId When coveringExpr is null,
* the id of the indexed column might match a query filter.
* @param tableScan The table scan on which the indexed expression is based
* @param filtersToCover the query conditions that may contain the desired filter
* @param allowIndexedJoinFilters Whether filters referencing other tables' columns are acceptable
* @param filterAction the desired disposition of the matched filter,
either EXCLUDE_FROM_POST_FILTERS or KEEP_IN_POST_FILTERS
* @return An IndexableExpression -- really just a pairing of a normalized form of expr with the
* potentially indexed expression on the left-hand-side and the potential index key expression on
* the right of a comparison operator, and a list of parameter bindings that are required for the
* index scan to be applicable.
* -- or null if there is no filter that matches the indexed expression
*/
private static IndexableExpression getIndexableExpressionFromFilters(ExpressionType targetComparator, ExpressionType altTargetComparator, AbstractExpression coveringExpr, int coveringColId, StmtTableScan tableScan, List<AbstractExpression> filtersToCover, boolean allowIndexedJoinFilters, boolean filterAction) {
List<AbstractExpression> binding = null;
AbstractExpression indexableExpr = null;
AbstractExpression otherExpr = null;
ComparisonExpression normalizedExpr = null;
AbstractExpression originalFilter = null;
for (AbstractExpression filter : filtersToCover) {
// ENG-8203: Not going to try to use index with sub-query expression
if (filter.hasSubquerySubexpression()) {
// SelectSubqueryExpression also can be scalar sub-query
continue;
}
// Expression type must be resolvable by an index scan
if ((filter.getExpressionType() == targetComparator) || (filter.getExpressionType() == altTargetComparator)) {
normalizedExpr = (ComparisonExpression) filter;
indexableExpr = filter.getLeft();
otherExpr = filter.getRight();
binding = bindingIfValidIndexedFilterOperand(tableScan, indexableExpr, otherExpr, coveringExpr, coveringColId);
if (binding != null) {
if (!allowIndexedJoinFilters) {
if (otherExpr.hasTupleValueSubexpression()) {
// This filter can not be used with the index, possibly due to interactions
// wih IN LIST processing that would require a three-way NLIJ.
binding = null;
continue;
}
}
// Additional restrictions apply to LIKE pattern arguments
if (targetComparator == ExpressionType.COMPARE_LIKE) {
if (otherExpr instanceof ParameterValueExpression) {
ParameterValueExpression pve = (ParameterValueExpression) otherExpr;
// Can't use an index for parameterized LIKE filters,
// e.g. "T1.column LIKE ?"
// UNLESS the parameter was artificially substituted
// for a user-specified constant AND that constant was a prefix pattern.
// In that case, the parameter has to be added to the bound list
// for this index/statement.
ConstantValueExpression cve = pve.getOriginalValue();
if (cve == null || !cve.isPrefixPatternString()) {
// the filter is not usable, so the binding is invalid
binding = null;
continue;
}
// Remember that the binding list returned by
// bindingIfValidIndexedFilterOperand above
// is often a "shared object" and is intended to be treated as immutable.
// To add a parameter to it, first copy the List.
List<AbstractExpression> moreBinding = new ArrayList<>(binding);
moreBinding.add(pve);
binding = moreBinding;
} else if (otherExpr instanceof ConstantValueExpression) {
// Can't use an index for non-prefix LIKE filters,
// e.g. " T1.column LIKE '%ish' "
ConstantValueExpression cve = (ConstantValueExpression) otherExpr;
if (!cve.isPrefixPatternString()) {
// The constant is not an index-friendly prefix pattern.
// the filter is not usable, so the binding is invalid
binding = null;
continue;
}
} else {
// Other cases are not indexable, e.g. " T1.column LIKE T2.column "
// the filter is not usable, so the binding is invalid
binding = null;
continue;
}
}
if (targetComparator == ExpressionType.COMPARE_IN) {
if (otherExpr.hasTupleValueSubexpression()) {
// This is a fancy edge case where the expression could only be indexed
// if it:
// A) does not reference the indexed table and
// B) has ee support for a three-way NLIJ where the table referenced in
// the list element expression feeds values from its current row to the
// Materialized scan which then re-evaluates its expressions to
// re-populate the temp table that drives the injected NLIJ with
// this index scan.
// This is a slightly more twisted variant of the three-way NLIJ that
// would be needed to support compound key indexing on a combination
// of (fixed) IN LIST elements and join key values from other tables.
// Punt for now on indexing this IN LIST filter.
// the filter is not usable, so the binding is invalid
binding = null;
continue;
}
if (otherExpr instanceof ParameterValueExpression) {
// It's OK to use an index for a parameterized IN filter,
// e.g. "T1.column IN ?"
// EVEN if the parameter was -- someday -- artificially substituted
// for an entire user-specified list of constants.
// As of now, that is beyond the capabilities of the ad hoc statement
// parameterizer, so "T1.column IN (3, 4)" can use the plan for
// "T1.column IN (?, ?)" that might have been originally cached for
// "T1.column IN (1, 2)" but "T1.column IN (1, 2, 3)" would need its own
// "T1.column IN (?, ?, ?)" plan, etc. per list element count.
} else //TODO: Some day, there may be an optimization here that allows an entire
// IN LIST of constants to be serialized as a single value instead of a
// VectorValue composed of ConstantValue arguments.
// What's TBD is whether that would get its own AbstractExpression class or
// just be a special case of ConstantValueExpression.
{
assert (otherExpr instanceof VectorValueExpression);
}
}
originalFilter = filter;
if (filterAction == EXCLUDE_FROM_POST_FILTERS) {
filtersToCover.remove(filter);
}
break;
}
}
if ((filter.getExpressionType() == ComparisonExpression.reverses.get(targetComparator)) || (filter.getExpressionType() == ComparisonExpression.reverses.get(altTargetComparator))) {
normalizedExpr = (ComparisonExpression) filter;
normalizedExpr = normalizedExpr.reverseOperator();
indexableExpr = filter.getRight();
otherExpr = filter.getLeft();
binding = bindingIfValidIndexedFilterOperand(tableScan, indexableExpr, otherExpr, coveringExpr, coveringColId);
if (binding != null) {
if (!allowIndexedJoinFilters) {
if (otherExpr.hasTupleValueSubexpression()) {
// This filter can not be used with the index, probably due to interactions
// with IN LIST processing of another key component that would require a
// three-way NLIJ to be injected.
binding = null;
continue;
}
}
originalFilter = filter;
if (filterAction == EXCLUDE_FROM_POST_FILTERS) {
filtersToCover.remove(filter);
}
break;
}
}
}
if (binding == null) {
// ran out of candidate filters.
return null;
}
return new IndexableExpression(originalFilter, normalizedExpr, binding);
}
use of org.voltdb.expressions.VectorValueExpression in project voltdb by VoltDB.
the class SubPlanAssembler method injectIndexedJoinWithMaterializedScan.
// Generate a plan for an IN-LIST-driven index scan
private static AbstractPlanNode injectIndexedJoinWithMaterializedScan(AbstractExpression listElements, IndexScanPlanNode scanNode) {
MaterializedScanPlanNode matScan = new MaterializedScanPlanNode();
assert (listElements instanceof VectorValueExpression || listElements instanceof ParameterValueExpression);
matScan.setRowData(listElements);
matScan.setSortDirection(scanNode.getSortDirection());
NestLoopIndexPlanNode nlijNode = new NestLoopIndexPlanNode();
nlijNode.setJoinType(JoinType.INNER);
nlijNode.addInlinePlanNode(scanNode);
nlijNode.addAndLinkChild(matScan);
// resolve the sort direction
nlijNode.resolveSortDirection();
return nlijNode;
}
Aggregations