Search in sources :

Example 1 with ConstantValueExpression

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

the class AbstractParsedStmt method parseValueExpression.

/**
     *
     * @param paramsById
     * @param exprNode
     * @return
     */
private AbstractExpression parseValueExpression(VoltXMLElement exprNode) {
    String isParam = exprNode.attributes.get("isparam");
    String isPlannerGenerated = exprNode.attributes.get("isplannergenerated");
    // A ParameterValueExpression is needed to represent any user-provided or planner-injected parameter.
    boolean needParameter = (isParam != null) && (isParam.equalsIgnoreCase("true"));
    // A ConstantValueExpression is needed to represent a constant in the statement,
    // EVEN if that constant has been "parameterized" by the plan caching code.
    ConstantValueExpression cve = null;
    boolean needConstant = (needParameter == false) || ((isPlannerGenerated != null) && (isPlannerGenerated.equalsIgnoreCase("true")));
    if (needConstant) {
        String type = exprNode.attributes.get("valuetype");
        VoltType vt = VoltType.typeFromString(type);
        assert (vt != VoltType.VOLTTABLE);
        cve = new ConstantValueExpression();
        cve.setValueType(vt);
        if ((vt != VoltType.NULL) && (vt != VoltType.NUMERIC)) {
            int size = vt.getMaxLengthInBytes();
            cve.setValueSize(size);
        }
        if (!needParameter && vt != VoltType.NULL) {
            String valueStr = exprNode.attributes.get("value");
            // given type.
            if (valueStr != null) {
                try {
                    switch(vt) {
                        case BIGINT:
                        case TIMESTAMP:
                            Long.valueOf(valueStr);
                            break;
                        case FLOAT:
                            Double.valueOf(valueStr);
                            break;
                        case DECIMAL:
                            VoltDecimalHelper.stringToDecimal(valueStr);
                            break;
                        default:
                            break;
                    }
                } catch (PlanningErrorException ex) {
                    // We're happy with these.
                    throw ex;
                } catch (NumberFormatException ex) {
                    throw new PlanningErrorException("Numeric conversion error to type " + vt.name() + " " + ex.getMessage().toLowerCase());
                } catch (Exception ex) {
                    throw new PlanningErrorException(ex.getMessage());
                }
            }
            cve.setValue(valueStr);
        }
    }
    if (needParameter) {
        long id = Long.parseLong(exprNode.attributes.get("id"));
        ParameterValueExpression expr = m_paramsById.get(id);
        assert (expr != null);
        if (needConstant) {
            expr.setOriginalValue(cve);
            cve.setValue(m_paramValues[expr.getParameterIndex()]);
        }
        return expr;
    }
    return cve;
}
Also used : VoltType(org.voltdb.VoltType) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ParameterValueExpression(org.voltdb.expressions.ParameterValueExpression) Constraint(org.voltdb.catalog.Constraint) JSONException(org.json_voltpatches.JSONException)

Example 2 with ConstantValueExpression

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

the class AbstractParsedStmt method getParameterOrConstantAsExpression.

protected AbstractExpression getParameterOrConstantAsExpression(long id, long value) {
    // parameter's type has been refined to INTEGER.
    if (id != -1) {
        return m_paramsById.get(id);
    }
    // The limit/offset is a non-parameterized literal value that needs to be wrapped in a
    // BIGINT constant so it can be used in the addition expression for the pushed-down limit.
    ConstantValueExpression constant = new ConstantValueExpression();
    constant.setValue(Long.toString(value));
    constant.refineValueType(VoltType.BIGINT, VoltType.BIGINT.getLengthInBytesForFixedTypes());
    return constant;
}
Also used : ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression)

Example 3 with ConstantValueExpression

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

the class JoinNode method applyTransitiveEquivalence.

private static List<AbstractExpression> applyTransitiveEquivalence(List<AbstractExpression> singleTableExprs, List<AbstractExpression> twoTableExprs) {
    ArrayList<AbstractExpression> simplifiedExprs = new ArrayList<>();
    HashMap<AbstractExpression, Set<AbstractExpression>> eqMap1 = new HashMap<>();
    ExpressionUtil.collectPartitioningFilters(singleTableExprs, eqMap1);
    for (AbstractExpression expr : twoTableExprs) {
        if (!expr.isColumnEquivalenceFilter()) {
            continue;
        }
        AbstractExpression leftExpr = expr.getLeft();
        AbstractExpression rightExpr = expr.getRight();
        assert (leftExpr instanceof TupleValueExpression && rightExpr instanceof TupleValueExpression);
        Set<AbstractExpression> eqSet1 = eqMap1.get(leftExpr);
        AbstractExpression singleExpr = leftExpr;
        if (eqSet1 == null) {
            eqSet1 = eqMap1.get(rightExpr);
            if (eqSet1 == null) {
                continue;
            }
            singleExpr = rightExpr;
        }
        for (AbstractExpression eqExpr : eqSet1) {
            if (eqExpr instanceof ConstantValueExpression) {
                if (singleExpr == leftExpr) {
                    expr.setLeft(eqExpr);
                } else {
                    expr.setRight(eqExpr);
                }
                simplifiedExprs.add(expr);
                // much sense, right?
                break;
            }
        }
    }
    twoTableExprs.removeAll(simplifiedExprs);
    return simplifiedExprs;
}
Also used : TupleValueExpression(org.voltdb.expressions.TupleValueExpression) Set(java.util.Set) HashSet(java.util.HashSet) AbstractExpression(org.voltdb.expressions.AbstractExpression) HashMap(java.util.HashMap) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ArrayList(java.util.ArrayList)

Example 4 with ConstantValueExpression

use of org.voltdb.expressions.ConstantValueExpression 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 5 with ConstantValueExpression

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

the class IndexCountPlanNode method createOrNull.

// Create an IndexCountPlanNode that replaces the parent aggregate and child
// indexscan IF the indexscan's end expressions are a form that can be
// modeled with an end key.
// The supported forms for end expression are:
//   - null
//   - one filter expression per index key component (ANDed together)
//     as "combined" for the IndexScan.
//   - fewer filter expressions than index key components with one of the
//     (the last) being a LT comparison.
//   - 1 fewer filter expressions than index key components,
//     but all ANDed equality filters
// The LT restriction comes because when index key prefixes are identical
// to the prefix-only end key, the entire index key sorts greater than the
// prefix-only end-key, because it is always longer.
// These prefix-equal cases would be missed in an EQ or LTE filter,
// causing undercounts.
// A prefix-only LT filter discards prefix-equal cases, so it is allowed.
// @return the IndexCountPlanNode or null if one is not possible.
public static IndexCountPlanNode createOrNull(IndexScanPlanNode isp, AggregatePlanNode apn) {
    // add support for reverse scan
    // for ASC scan, check endExpression;
    // for DESC scan (isReverseScan()), check the searchkeys
    List<AbstractExpression> endKeys = new ArrayList<>();
    // Translate the index scan's end condition into a list of end key
    // expressions and note the comparison operand of the last one.
    // Initially assume it to be an equality filter.
    IndexLookupType endType = IndexLookupType.EQ;
    List<AbstractExpression> endComparisons = ExpressionUtil.uncombinePredicate(isp.getEndExpression());
    for (AbstractExpression ae : endComparisons) {
        // LT or LTE expression that resets the end type.
        assert (endType == IndexLookupType.EQ);
        ExpressionType exprType = ae.getExpressionType();
        if (exprType == ExpressionType.COMPARE_LESSTHAN) {
            endType = IndexLookupType.LT;
        } else if (exprType == ExpressionType.COMPARE_LESSTHANOREQUALTO) {
            endType = IndexLookupType.LTE;
        } else {
            assert (exprType == ExpressionType.COMPARE_EQUAL || exprType == ExpressionType.COMPARE_NOTDISTINCT);
        }
        // PlanNodes all need private deep copies of expressions
        // so that the resolveColumnIndexes results
        // don't get bashed by other nodes or subsequent planner runs
        endKeys.add(ae.getRight().clone());
    }
    int indexSize = 0;
    String jsonstring = isp.getCatalogIndex().getExpressionsjson();
    List<ColumnRef> indexedColRefs = null;
    List<AbstractExpression> indexedExprs = null;
    if (jsonstring.isEmpty()) {
        indexedColRefs = CatalogUtil.getSortedCatalogItems(isp.getCatalogIndex().getColumns(), "index");
        indexSize = indexedColRefs.size();
    } else {
        try {
            indexedExprs = AbstractExpression.fromJSONArrayString(jsonstring, isp.getTableScan());
            indexSize = indexedExprs.size();
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    int searchKeySize = isp.getSearchKeyExpressions().size();
    int endKeySize = endKeys.size();
    if (!isp.isReverseScan() && endType != IndexLookupType.LT && endKeySize > 0 && endKeySize < indexSize) {
        // That is, when a prefix-only key exists and does not use LT.
        if (endType != IndexLookupType.EQ || searchKeySize != indexSize || endKeySize < indexSize - 1) {
            return null;
        }
        // To use an index count for an equality search of da compound key,
        // both the search key and end key must have a component for each
        // index component.
        // If the search key is long enough but the end key is one component
        // short, it can be patched with a type-appropriate max key value
        // (if one exists for the type), but the end key comparison needs to
        // change from EQ to LTE to compensate.
        VoltType missingEndKeyType;
        // and get the missing key component's indexed expression.
        if (jsonstring.isEmpty()) {
            int lastIndex = indexedColRefs.get(endKeySize).getColumn().getIndex();
            for (AbstractExpression expr : endComparisons) {
                if (((TupleValueExpression) (expr.getLeft())).getColumnIndex() == lastIndex) {
                    return null;
                }
            }
            int catalogTypeCode = indexedColRefs.get(endKeySize).getColumn().getType();
            missingEndKeyType = VoltType.get((byte) catalogTypeCode);
        } else {
            AbstractExpression lastIndexedExpr = indexedExprs.get(endKeySize);
            for (AbstractExpression expr : endComparisons) {
                if (expr.getLeft().bindingToIndexedExpression(lastIndexedExpr) != null) {
                    return null;
                }
            }
            missingEndKeyType = lastIndexedExpr.getValueType();
        }
        String maxValueForType = missingEndKeyType.getMaxValueForKeyPadding();
        // for which all legal values are less than or equal to it.
        if (maxValueForType == null) {
            return null;
        }
        ConstantValueExpression maxKey = new ConstantValueExpression();
        maxKey.setValueType(missingEndKeyType);
        maxKey.setValue(maxValueForType);
        maxKey.setValueSize(missingEndKeyType.getLengthInBytesForFixedTypes());
        endType = IndexLookupType.LTE;
        endKeys.add(maxKey);
    }
    // DESC case
    if (searchKeySize > 0 && searchKeySize < indexSize) {
        return null;
    }
    return new IndexCountPlanNode(isp, apn, endType, endKeys);
}
Also used : IndexLookupType(org.voltdb.types.IndexLookupType) ArrayList(java.util.ArrayList) JSONException(org.json_voltpatches.JSONException) AbstractExpression(org.voltdb.expressions.AbstractExpression) VoltType(org.voltdb.VoltType) ConstantValueExpression(org.voltdb.expressions.ConstantValueExpression) ColumnRef(org.voltdb.catalog.ColumnRef) ExpressionType(org.voltdb.types.ExpressionType)

Aggregations

ConstantValueExpression (org.voltdb.expressions.ConstantValueExpression)15 AbstractExpression (org.voltdb.expressions.AbstractExpression)12 ParameterValueExpression (org.voltdb.expressions.ParameterValueExpression)8 TupleValueExpression (org.voltdb.expressions.TupleValueExpression)7 ArrayList (java.util.ArrayList)5 HashSet (java.util.HashSet)3 Set (java.util.Set)3 VoltType (org.voltdb.VoltType)3 ColumnRef (org.voltdb.catalog.ColumnRef)3 StmtTableScan (org.voltdb.planner.parseinfo.StmtTableScan)3 SchemaColumn (org.voltdb.plannodes.SchemaColumn)3 JSONException (org.json_voltpatches.JSONException)2 Column (org.voltdb.catalog.Column)2 Constraint (org.voltdb.catalog.Constraint)2 Index (org.voltdb.catalog.Index)2 Table (org.voltdb.catalog.Table)2 OperatorExpression (org.voltdb.expressions.OperatorExpression)2 HashMap (java.util.HashMap)1 AggregateExpression (org.voltdb.expressions.AggregateExpression)1 ComparisonExpression (org.voltdb.expressions.ComparisonExpression)1