Search in sources :

Example 1 with ComparisonExpression

use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.

the class AbstractParsedStmt method rejectDisallowedRowOpExpressions.

private void rejectDisallowedRowOpExpressions(AbstractExpression expr) {
    ExpressionType exprType = expr.getExpressionType();
    // searching for row op subquery expressions.
    if (ExpressionType.CONJUNCTION_AND == exprType || ExpressionType.CONJUNCTION_OR == exprType) {
        rejectDisallowedRowOpExpressions(expr.getLeft());
        rejectDisallowedRowOpExpressions(expr.getRight());
        return;
    }
    if (ExpressionType.OPERATOR_NOT == exprType) {
        rejectDisallowedRowOpExpressions(expr.getLeft());
    }
    // The problem cases are all comparison ops.
    if (!(expr instanceof ComparisonExpression)) {
        return;
    }
    // The problem cases all have row expressions as an operand.
    AbstractExpression rowExpression = expr.getLeft();
    if (rowExpression instanceof RowSubqueryExpression) {
        rejectDisallowedRowColumns(rowExpression);
    }
    rowExpression = expr.getRight();
    if (rowExpression instanceof RowSubqueryExpression) {
        rejectDisallowedRowColumns(rowExpression);
    }
}
Also used : ComparisonExpression(org.voltdb.expressions.ComparisonExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) RowSubqueryExpression(org.voltdb.expressions.RowSubqueryExpression) ExpressionType(org.voltdb.types.ExpressionType)

Example 2 with ComparisonExpression

use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.

the class ReplaceWithIndexLimit method recursivelyApply.

@Override
protected AbstractPlanNode recursivelyApply(AbstractPlanNode plan) {
    assert (plan != null);
    // depth first:
    //     Find AggregatePlanNode with exactly one child
    //     where that child is an AbstractScanPlanNode.
    //     Replace qualifying SeqScanPlanNode with an
    //     IndexScanPlanNode with an inlined LimitPlanNode;
    //     or appending the LimitPlanNode to the existing
    //     qualified IndexScanPlanNode.
    ArrayList<AbstractPlanNode> children = new ArrayList<AbstractPlanNode>();
    for (int i = 0; i < plan.getChildCount(); i++) children.add(plan.getChild(i));
    for (AbstractPlanNode child : children) {
        // TODO this will break when children feed multiple parents
        AbstractPlanNode newChild = recursivelyApply(child);
        // Do a graft into the (parent) plan only if a replacement for a child was found.
        if (newChild == child) {
            continue;
        }
        child.removeFromGraph();
        plan.addAndLinkChild(newChild);
    }
    // check for an aggregation of the right form
    if ((plan instanceof AggregatePlanNode) == false)
        return plan;
    assert (plan.getChildCount() == 1);
    AggregatePlanNode aggplan = (AggregatePlanNode) plan;
    // handle one single min() / max() now
    // TODO: combination of [min(), max(), count()]
    SortDirectionType sortDirection = SortDirectionType.INVALID;
    if (aggplan.isTableMin()) {
        sortDirection = SortDirectionType.ASC;
    } else if (aggplan.isTableMax()) {
        sortDirection = SortDirectionType.DESC;
    } else {
        return plan;
    }
    AbstractPlanNode child = plan.getChild(0);
    AbstractExpression aggExpr = aggplan.getFirstAggregateExpression();
    // for a SEQSCAN, replace it with a INDEXSCAN node with an inline LIMIT plan node
    if (child instanceof SeqScanPlanNode) {
        // should have other index access plan if any qualified index found for the predicate
        if (((SeqScanPlanNode) child).getPredicate() != null) {
            return plan;
        }
        if (((AbstractScanPlanNode) child).isSubQuery()) {
            return plan;
        }
        // create an empty bindingExprs list, used for store (possible) bindings for adHoc query
        ArrayList<AbstractExpression> bindings = new ArrayList<AbstractExpression>();
        Index ret = findQualifiedIndex(((SeqScanPlanNode) child), aggExpr, bindings);
        if (ret == null) {
            return plan;
        } else {
            // 1. create one INDEXSCAN plan node with inlined LIMIT
            // and replace the SEQSCAN node with it
            // 2. we know which end row we want to fetch, so it's safe to
            // specify sorting direction here
            IndexScanPlanNode ispn = new IndexScanPlanNode((SeqScanPlanNode) child, aggplan, ret, sortDirection);
            ispn.setBindings(bindings);
            assert (ispn.getSearchKeyExpressions().size() == 0);
            if (sortDirection == SortDirectionType.ASC) {
                assert (aggplan.isTableMin());
                ispn.setSkipNullPredicate(0);
            }
            LimitPlanNode lpn = new LimitPlanNode();
            lpn.setLimit(1);
            lpn.setOffset(0);
            ispn.addInlinePlanNode(lpn);
            // remove old SeqScan node and link the new generated IndexScan node
            plan.clearChildren();
            plan.addAndLinkChild(ispn);
            return plan;
        }
    }
    if ((child instanceof IndexScanPlanNode) == false) {
        return plan;
    }
    // already have the IndexScanPlanNode
    IndexScanPlanNode ispn = (IndexScanPlanNode) child;
    // we added for reverse scan purpose only
    if (((IndexScanPlanNode) child).getPredicate() != null && !((IndexScanPlanNode) child).isPredicatesOptimizableForAggregate()) {
        return plan;
    }
    // Guard against (possible future?) cases of indexable subquery.
    if (((AbstractScanPlanNode) child).isSubQuery()) {
        return plan;
    }
    // 2. Handle equality filters and one other comparison operator (<, <=, >, >=), see comments below
    if (ispn.getLookupType() != IndexLookupType.EQ && Math.abs(ispn.getSearchKeyExpressions().size() - ExpressionUtil.uncombinePredicate(ispn.getEndExpression()).size()) > 1) {
        return plan;
    }
    // exprs will be used as filterExprs to check the index
    // For forward scan, the initial value is endExprs and might be changed in different values in variant cases
    // For reverse scan, the initial value is initialExprs which is the "old" endExprs
    List<AbstractExpression> exprs;
    int numOfSearchKeys = ispn.getSearchKeyExpressions().size();
    if (ispn.getLookupType() == IndexLookupType.LT || ispn.getLookupType() == IndexLookupType.LTE) {
        exprs = ExpressionUtil.uncombinePredicate(ispn.getInitialExpression());
        numOfSearchKeys -= 1;
    } else {
        exprs = ExpressionUtil.uncombinePredicate(ispn.getEndExpression());
    }
    int numberOfExprs = exprs.size();
    /* Retrieve the index expressions from the target index. (ENG-8819, Ethan)
         * This is because we found that for the following two queries:
         *     #1: explain select max(c2/2) from t where c1=1 and c2/2<=3;
         *     #2: explain select max(c2/2) from t where c1=1 and c2/2<=?;
         * We can get an inline limit 1 for #2 but not for #1. This is because all constants in #1 got parameterized.
         * The result is that the query cannot pass the bindingToIndexedExpression() tests below
         * because we lost all the constant value expressions (cannot attempt to bind a pve to a pve!).
         * Those constant values expressions can only be accessed from the idnex.
         * We will not add those bindings to the ispn.getBindings() here because they will be added anyway in checkIndex().
         * PS: For this case (i.e. index on expressions), checkIndex() will call checkExpressionIndex(),
         * where bindings will be added.
         */
    Index indexToUse = ispn.getCatalogIndex();
    String tableAlias = ispn.getTargetTableAlias();
    List<AbstractExpression> indexedExprs = null;
    if (!indexToUse.getExpressionsjson().isEmpty()) {
        StmtTableScan tableScan = m_parsedStmt.getStmtTableScanByAlias(tableAlias);
        try {
            indexedExprs = AbstractExpression.fromJSONArrayString(indexToUse.getExpressionsjson(), tableScan);
        } catch (JSONException e) {
            e.printStackTrace();
            assert (false);
            return plan;
        }
    }
    /* If there is only 1 difference between searchkeyExprs and endExprs,
         * 1. trivial filters can be discarded, 2 possibilities:
         *      a. SELECT MIN(X) FROM T WHERE [other prefix filters] X < / <= ?
         *         <=> SELECT MIN(X) FROM T WHERE [other prefix filters] && the X < / <= ? filter
         *      b. SELECT MAX(X) FROM T WHERE X > / >= ?
         *         <=> SELECT MAX(X) FROM T with post-filter
         * 2. filter should act as equality filter, 2 possibilities
         *      SELECT MIN(X) FROM T WHERE [other prefix filters] X > / >= ?
         *      SELECT MAX(X) FROM T WHERE [other prefix filters] X < / <= ?

         * check if there is other filters for SELECT MAX(X) FROM T WHERE [other prefix filter AND ] X > / >= ?
         * but we should allow SELECT MAX(X) FROM T WHERE X = ?

         * This is for queries having MAX() but no ORDER BY. (ENG-8819, Ethan)
         * sortDirection == DESC if max, ASC if min. ispn.getSortDirection() == INVALID if no ORDER BY. */
    if (sortDirection == SortDirectionType.DESC && ispn.getSortDirection() == SortDirectionType.INVALID) {
        /* numberOfExprs = exprs.size(), exprs are initial expressions for reversed index scans (lookupType LT, LTE),
             * are end expressions for forward index scans (lookupType GT, GTE, EQ).
             * Note, lookupType doesn't decide the scan direction for sure. MIN(X) where X < ? is still a forward scan.
             * X < ? will be a post filter for the scan rather than an initial expression. */
        if (numberOfExprs == 1) {
            // e.g.: explain select max(c2/2) from t where c2/2<=3;
            // In this case, as long as the where condition (exprs.get(0)) matches the aggregation argument, continue.
            AbstractExpression exprToBind = indexedExprs == null ? exprs.get(0).getLeft() : indexedExprs.get(0);
            if (aggExpr.bindingToIndexedExpression(exprToBind) == null) {
                return plan;
            }
        } else if (numberOfExprs > 1) {
            // ENG-4016: Optimization for query SELECT MAX(X) FROM T WHERE [other prefix filters] X < / <= ?
            // Just keep trying, don't return early.
            boolean earlyReturn = true;
            for (int i = 0; i < numberOfExprs; ++i) {
                AbstractExpression expr = exprs.get(i);
                AbstractExpression indexedExpr = indexedExprs == null ? expr.getLeft() : indexedExprs.get(i);
                if (aggExpr.bindingToIndexedExpression(indexedExpr) != null && (expr.getExpressionType() == ExpressionType.COMPARE_LESSTHANOREQUALTO || expr.getExpressionType() == ExpressionType.COMPARE_LESSTHAN || expr.getExpressionType() == ExpressionType.COMPARE_EQUAL)) {
                    earlyReturn = false;
                    break;
                }
            }
            if (earlyReturn) {
                return plan;
            }
        }
    }
    // have an upper bound: # of endingExpr is more than # of searchExpr
    if (numberOfExprs > numOfSearchKeys) {
        AbstractExpression lastEndExpr = exprs.get(numberOfExprs - 1);
        // check last ending condition, see whether it is
        //      SELECT MIN(X) FROM T WHERE [other prefix filters] X < / <= ? or
        // other filters will be checked later
        AbstractExpression exprToBind = indexedExprs == null ? lastEndExpr.getLeft() : indexedExprs.get(numberOfExprs - 1);
        if ((lastEndExpr.getExpressionType() == ExpressionType.COMPARE_LESSTHAN || lastEndExpr.getExpressionType() == ExpressionType.COMPARE_LESSTHANOREQUALTO) && aggExpr.bindingToIndexedExpression(exprToBind) != null) {
            exprs.remove(lastEndExpr);
        }
    }
    // and we can take advantage of that
    if (checkIndex(ispn.getCatalogIndex(), aggExpr, exprs, ispn.getBindings(), tableAlias)) {
        // we know which end we want to fetch, set the sort direction
        ispn.setSortDirection(sortDirection);
        // for SELECT MIN(X) FROM T WHERE [prefix filters] = ?
        if (numberOfExprs == numOfSearchKeys && sortDirection == SortDirectionType.ASC) {
            if (ispn.getLookupType() == IndexLookupType.GTE) {
                assert (aggplan.isTableMin());
                ispn.setSkipNullPredicate(numOfSearchKeys);
            }
        }
        // reset the IndexLookupType, remove "added" searchKey, add back to endExpression, and clear "added" predicate
        if (sortDirection == SortDirectionType.ASC && (ispn.getLookupType() == IndexLookupType.LT || ispn.getLookupType() == IndexLookupType.LTE)) {
            ispn.setLookupType(IndexLookupType.GTE);
            ispn.removeLastSearchKey();
            ispn.addEndExpression(ExpressionUtil.uncombinePredicate(ispn.getInitialExpression()).get(numberOfExprs - 1));
            ispn.setSkipNullPredicate(numOfSearchKeys);
            ispn.resetPredicate();
        }
        // add an inline LIMIT plan node to this index scan plan node
        LimitPlanNode lpn = new LimitPlanNode();
        lpn.setLimit(1);
        lpn.setOffset(0);
        ispn.addInlinePlanNode(lpn);
        //                                              |__LimitPlanNode
        if (sortDirection == SortDirectionType.DESC && !ispn.getSearchKeyExpressions().isEmpty() && exprs.isEmpty() && ExpressionUtil.uncombinePredicate(ispn.getInitialExpression()).isEmpty()) {
            AbstractExpression newPredicate = new ComparisonExpression();
            if (ispn.getLookupType() == IndexLookupType.GT)
                newPredicate.setExpressionType(ExpressionType.COMPARE_GREATERTHAN);
            if (ispn.getLookupType() == IndexLookupType.GTE)
                newPredicate.setExpressionType(ExpressionType.COMPARE_GREATERTHANOREQUALTO);
            newPredicate.setRight(ispn.getSearchKeyExpressions().get(0));
            newPredicate.setLeft(aggExpr);
            newPredicate.setValueType(aggExpr.getValueType());
            ispn.clearSearchKeyExpression();
            aggplan.setPrePredicate(newPredicate);
        }
    }
    return plan;
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) AbstractScanPlanNode(org.voltdb.plannodes.AbstractScanPlanNode) AggregatePlanNode(org.voltdb.plannodes.AggregatePlanNode) IndexScanPlanNode(org.voltdb.plannodes.IndexScanPlanNode) ArrayList(java.util.ArrayList) JSONException(org.json_voltpatches.JSONException) Index(org.voltdb.catalog.Index) SortDirectionType(org.voltdb.types.SortDirectionType) StmtTableScan(org.voltdb.planner.parseinfo.StmtTableScan) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) ComparisonExpression(org.voltdb.expressions.ComparisonExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) LimitPlanNode(org.voltdb.plannodes.LimitPlanNode)

Example 3 with ComparisonExpression

use of org.voltdb.expressions.ComparisonExpression 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);
}
Also used : ComparisonExpression(org.voltdb.expressions.ComparisonExpression) VectorValueExpression(org.voltdb.expressions.VectorValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ArrayList(java.util.ArrayList) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression)

Example 4 with ComparisonExpression

use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.

the class SubPlanAssembler method isPartialIndexPredicateCovered.

/**
     * Split the index WHERE clause into a list of sub-expressions and process
     * each expression separately searching the query (or matview) for a
     * covering expression for each of these expressions.
     * All index WHERE sub-expressions must be covered to enable the index.
     * Collect the query expressions that EXACTLY match the index expression.
     * They can be eliminated from the post-filters as an optimization.
     *
     * @param tableScan The source table.
     * @param coveringExprs The set of query predicate expressions.
     * @param index The partial index to cover.
     * @param exactMatchCoveringExprs The output subset of the query predicates that EXACTLY match the
     *        index predicate expression(s)
     * @return TRUE if the index has a predicate that is completely covered by the query expressions.
     */
public static boolean isPartialIndexPredicateCovered(StmtTableScan tableScan, List<AbstractExpression> coveringExprs, String predicatejson, List<AbstractExpression> exactMatchCoveringExprs) {
    assert (!predicatejson.isEmpty());
    AbstractExpression indexPredicate = null;
    try {
        indexPredicate = AbstractExpression.fromJSONString(predicatejson, tableScan);
    } catch (JSONException e) {
        e.printStackTrace();
        assert (false);
        return false;
    }
    List<AbstractExpression> exprsToCover = ExpressionUtil.uncombinePredicate(indexPredicate);
    for (AbstractExpression coveringExpr : coveringExprs) {
        if (exprsToCover.isEmpty()) {
            // We are done there. All the index predicate expressions are covered.
            break;
        }
        // Each covering expression and its reversed copy need to be tested for the index expression coverage.
        AbstractExpression reversedCoveringExpr = null;
        ExpressionType reverseCoveringType = ComparisonExpression.reverses.get(coveringExpr.getExpressionType());
        if (reverseCoveringType != null) {
            // reverse the expression
            reversedCoveringExpr = new ComparisonExpression(reverseCoveringType, coveringExpr.getRight(), coveringExpr.getLeft());
        }
        // Exact match first.
        if (removeExactMatchCoveredExpressions(coveringExpr, exprsToCover)) {
            exactMatchCoveringExprs.add(coveringExpr);
        }
        // Try the reversed expression for the exact match
        if (reversedCoveringExpr != null && removeExactMatchCoveredExpressions(reversedCoveringExpr, exprsToCover)) {
            // It is the original expression that we need to remember
            exactMatchCoveringExprs.add(coveringExpr);
        }
    }
    // Handle the remaining NOT NULL index predicate expressions that can be covered by NULL rejecting expressions
    exprsToCover = removeNotNullCoveredExpressions(tableScan, coveringExprs, exprsToCover);
    // All index predicate expressions must be covered for index to be selected
    return exprsToCover.isEmpty();
}
Also used : ComparisonExpression(org.voltdb.expressions.ComparisonExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) JSONException(org.json_voltpatches.JSONException) ExpressionType(org.voltdb.types.ExpressionType)

Example 5 with ComparisonExpression

use of org.voltdb.expressions.ComparisonExpression in project voltdb by VoltDB.

the class TestPlansSubQueries method testParameters.

public void testParameters() {
    AbstractPlanNode pn = compile("select A1 FROM (SELECT A A1 FROM R1 WHERE A > ? LIMIT 10) TEMP WHERE A1 < ?");
    pn = pn.getChild(0);
    assertTrue(pn instanceof SeqScanPlanNode);
    AbstractExpression p = ((SeqScanPlanNode) pn).getPredicate();
    assertTrue(p != null);
    assertTrue(p instanceof ComparisonExpression);
    AbstractExpression cp = p.getLeft();
    assertTrue(cp instanceof TupleValueExpression);
    cp = p.getRight();
    assertTrue(cp instanceof ParameterValueExpression);
    assertEquals(1, ((ParameterValueExpression) cp).getParameterIndex().intValue());
    assertTrue(pn.getChildCount() == 1);
    assertTrue(pn.getChild(0) instanceof SeqScanPlanNode);
    SeqScanPlanNode sc = (SeqScanPlanNode) pn.getChild(0);
    assertTrue(sc.getPredicate() != null);
    p = sc.getPredicate();
    assertTrue(p instanceof ComparisonExpression);
    cp = p.getRight();
    assertTrue(cp instanceof ParameterValueExpression);
    assertEquals(0, ((ParameterValueExpression) cp).getParameterIndex().intValue());
}
Also used : AbstractPlanNode(org.voltdb.plannodes.AbstractPlanNode) SeqScanPlanNode(org.voltdb.plannodes.SeqScanPlanNode) ComparisonExpression(org.voltdb.expressions.ComparisonExpression) TupleValueExpression(org.voltdb.expressions.TupleValueExpression) AbstractExpression(org.voltdb.expressions.AbstractExpression) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression)

Aggregations

AbstractExpression (org.voltdb.expressions.AbstractExpression)12 ComparisonExpression (org.voltdb.expressions.ComparisonExpression)12 ExpressionType (org.voltdb.types.ExpressionType)6 ArrayList (java.util.ArrayList)4 JSONException (org.json_voltpatches.JSONException)4 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)3 SeqScanPlanNode (org.voltdb.plannodes.SeqScanPlanNode)3 OperatorExpression (org.voltdb.expressions.OperatorExpression)2 ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)2 RowSubqueryExpression (org.voltdb.expressions.RowSubqueryExpression)2 SelectSubqueryExpression (org.voltdb.expressions.SelectSubqueryExpression)2 AbstractPlanNode (org.voltdb.plannodes.AbstractPlanNode)2 VoltXMLElement (org.hsqldb_voltpatches.VoltXMLElement)1 VoltType (org.voltdb.VoltType)1 Column (org.voltdb.catalog.Column)1 ColumnRef (org.voltdb.catalog.ColumnRef)1 Constraint (org.voltdb.catalog.Constraint)1 Index (org.voltdb.catalog.Index)1 ConjunctionExpression (org.voltdb.expressions.ConjunctionExpression)1 ConstantValueExpression (org.voltdb.expressions.ConstantValueExpression)1