package org.infinispan.objectfilter.impl.predicateindex.be; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.infinispan.objectfilter.impl.MetadataAdapter; import org.infinispan.objectfilter.impl.predicateindex.EqualsCondition; import org.infinispan.objectfilter.impl.predicateindex.IntervalPredicate; import org.infinispan.objectfilter.impl.predicateindex.IsNullCondition; import org.infinispan.objectfilter.impl.predicateindex.LikeCondition; import org.infinispan.objectfilter.impl.predicateindex.Predicate; import org.infinispan.objectfilter.impl.syntax.AndExpr; import org.infinispan.objectfilter.impl.syntax.BooleanExpr; import org.infinispan.objectfilter.impl.syntax.BooleanOperatorExpr; import org.infinispan.objectfilter.impl.syntax.ComparisonExpr; import org.infinispan.objectfilter.impl.syntax.ConstantBooleanExpr; import org.infinispan.objectfilter.impl.syntax.ConstantValueExpr; import org.infinispan.objectfilter.impl.syntax.IsNullExpr; import org.infinispan.objectfilter.impl.syntax.LikeExpr; import org.infinispan.objectfilter.impl.syntax.NotExpr; import org.infinispan.objectfilter.impl.syntax.OrExpr; import org.infinispan.objectfilter.impl.syntax.PrimaryPredicateExpr; import org.infinispan.objectfilter.impl.syntax.PropertyValueExpr; import org.infinispan.objectfilter.impl.util.Interval; /** * Creates a BETree out of a BooleanExpr. * * @author anistor@redhat.com * @since 7.0 */ public final class BETreeMaker<AttributeId extends Comparable<AttributeId>> { private final MetadataAdapter<?, ?, AttributeId> metadataAdapter; private final boolean useIntervals; public BETreeMaker(MetadataAdapter<?, ?, AttributeId> metadataAdapter, boolean useIntervals) { this.metadataAdapter = metadataAdapter; this.useIntervals = useIntervals; } public BETree make(BooleanExpr booleanExpr, Map<String, Object> namedParameters) { List<BENode> nodes = new ArrayList<>(); List<Integer> treeCounters = new ArrayList<>(); if (booleanExpr == null) { treeCounters.add(BETree.EXPR_TRUE); } else if (booleanExpr instanceof ConstantBooleanExpr) { treeCounters.add(((ConstantBooleanExpr) booleanExpr).getValue() ? BETree.EXPR_TRUE : BETree.EXPR_FALSE); } else { preorderTraversal(null, booleanExpr, nodes, treeCounters, namedParameters); } int[] countersArray = new int[treeCounters.size()]; for (int i = 0; i < countersArray.length; i++) { countersArray[i] = treeCounters.get(i); } return new BETree(nodes.toArray(new BENode[nodes.size()]), countersArray); } private void preorderTraversal(BENode parent, BooleanExpr child, List<BENode> nodes, List<Integer> treeCounters, Map<String, Object> namedParameters) { if (child instanceof NotExpr) { PrimaryPredicateExpr condition = (PrimaryPredicateExpr) ((NotExpr) child).getChild(); makePredicateNode(parent, nodes, treeCounters, condition, true, namedParameters); } else if (child instanceof PrimaryPredicateExpr) { PrimaryPredicateExpr condition = (PrimaryPredicateExpr) child; makePredicateNode(parent, nodes, treeCounters, condition, false, namedParameters); } else if (child instanceof OrExpr) { makeBooleanOperatorNode((OrExpr) child, nodes, treeCounters, new OrNode(parent), namedParameters); } else if (child instanceof AndExpr) { makeBooleanOperatorNode((AndExpr) child, nodes, treeCounters, new AndNode(parent), namedParameters); } else { throw new IllegalStateException("Unexpected *Expr node type: " + child); } } private void makePredicateNode(BENode parent, List<BENode> nodes, List<Integer> treeCounters, PrimaryPredicateExpr condition, boolean isNegated, Map<String, Object> namedParameters) { final PropertyValueExpr pve = (PropertyValueExpr) condition.getChild(); final List<AttributeId> path = metadataAdapter.mapPropertyNamePathToFieldIdPath(pve.getPropertyPath().asArrayPath()); final boolean isRepeated = pve.isRepeated(); if (condition instanceof ComparisonExpr) { ComparisonExpr expr = (ComparisonExpr) condition; ConstantValueExpr right = (ConstantValueExpr) expr.getRightChild(); Comparable rightConstant = right.getConstantValueAs(pve.getPrimitiveType(), namedParameters); switch (expr.getComparisonType()) { case NOT_EQUAL: if (useIntervals) { if (!(parent instanceof OrNode)) { parent = new OrNode(parent); int size = nodes.size(); parent.setLocation(size, size + 4); nodes.add(parent); treeCounters.add(3); } // the special case of non-equality is transformed into two intervals, excluding the compared value, + an IS NULL predicate addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(Interval.getMinusInf(), false, rightConstant, false))); addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(rightConstant, false, Interval.getPlusInf(), false))); addPredicateNode(parent, nodes, treeCounters, isNegated, path, new Predicate<>(isRepeated, IsNullCondition.INSTANCE)); } else { addPredicateNode(parent, nodes, treeCounters, !isNegated, path, new Predicate<>(isRepeated, new EqualsCondition(rightConstant))); } break; case EQUAL: if (useIntervals) { addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(rightConstant, true, rightConstant, true))); } else { addPredicateNode(parent, nodes, treeCounters, isNegated, path, new Predicate<>(isRepeated, new EqualsCondition(rightConstant))); } break; case LESS: addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(Interval.getMinusInf(), false, rightConstant, false))); break; case LESS_OR_EQUAL: addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(Interval.getMinusInf(), false, rightConstant, true))); break; case GREATER: addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(rightConstant, false, Interval.getPlusInf(), false))); break; case GREATER_OR_EQUAL: addPredicateNode(parent, nodes, treeCounters, isNegated, path, new IntervalPredicate(isRepeated, new Interval(rightConstant, true, Interval.getPlusInf(), false))); break; default: throw new IllegalStateException("Unexpected comparison type: " + expr.getComparisonType()); } } else if (condition instanceof IsNullExpr) { addPredicateNode(parent, nodes, treeCounters, isNegated, path, new Predicate<>(isRepeated, IsNullCondition.INSTANCE)); } else if (condition instanceof LikeExpr) { LikeExpr likeExpr = (LikeExpr) condition; addPredicateNode(parent, nodes, treeCounters, isNegated, path, new Predicate<>(isRepeated, new LikeCondition(likeExpr.getPattern(namedParameters), likeExpr.getEscapeChar()))); } else { throw new IllegalStateException("Unexpected condition type (" + condition.getClass().getSimpleName() + "): " + condition); } } private void addPredicateNode(BENode parent, List<BENode> nodes, List<Integer> treeCounters, boolean isNegated, List<AttributeId> path, Predicate predicate) { PredicateNode predicateNode = new PredicateNode<>(parent, predicate, isNegated, path); int size = nodes.size(); predicateNode.setLocation(size, size + 1); nodes.add(predicateNode); treeCounters.add(1); } private void makeBooleanOperatorNode(BooleanOperatorExpr child, List<BENode> nodes, List<Integer> treeCounters, BENode node, Map<String, Object> namedParameters) { int index = nodes.size(); nodes.add(node); List<BooleanExpr> children = child.getChildren(); treeCounters.add(children.size()); for (BooleanExpr c : children) { preorderTraversal(node, c, nodes, treeCounters, namedParameters); } node.setLocation(index, nodes.size()); } }