Java Code Examples for org.apache.calcite.rex.RexNode#isAlwaysTrue()

The following examples show how to use org.apache.calcite.rex.RexNode#isAlwaysTrue() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: RelMdDistinctRowCount.java    From Bats with Apache License 2.0 6 votes vote down vote up
public Double getDistinctRowCount(Filter rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  // REVIEW zfong 4/18/06 - In the Broadbase code, duplicates are not
  // removed from the two filter lists.  However, the code below is
  // doing so.
  RexNode unionPreds =
      RelMdUtil.unionPreds(
          rel.getCluster().getRexBuilder(),
          predicate,
          rel.getCondition());

  return mq.getDistinctRowCount(rel.getInput(), groupKey, unionPreds);
}
 
Example 2
Source File: JoinUtils.java    From Bats with Apache License 2.0 6 votes vote down vote up
public static JoinCategory getJoinCategory(RelNode left, RelNode right, RexNode condition,
    List<Integer> leftKeys, List<Integer> rightKeys, List<Boolean> filterNulls) {
  if (condition.isAlwaysTrue()) {
    return JoinCategory.CARTESIAN;
  }
  leftKeys.clear();
  rightKeys.clear();
  filterNulls.clear();
  RexNode remaining = RelOptUtil.splitJoinCondition(left, right, condition, leftKeys, rightKeys, filterNulls);

  if (!remaining.isAlwaysTrue() || (leftKeys.size() == 0 || rightKeys.size() == 0) ) {
    // for practical purposes these cases could be treated as inequality
    return JoinCategory.INEQUALITY;
  }
  return JoinCategory.EQUALITY;
}
 
Example 3
Source File: LoptMultiJoin.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Sets bitmaps indicating which factors and fields each join filter
 * references
 */
private void setJoinFilterRefs() {
  fieldsRefByJoinFilter = new HashMap<>();
  factorsRefByJoinFilter = new HashMap<>();
  ListIterator<RexNode> filterIter = allJoinFilters.listIterator();
  while (filterIter.hasNext()) {
    RexNode joinFilter = filterIter.next();

    // ignore the literal filter; if necessary, we'll add it back
    // later
    if (joinFilter.isAlwaysTrue()) {
      filterIter.remove();
    }
    ImmutableBitSet factorRefBitmap =
        getJoinFilterFactorBitmap(joinFilter, true);
    factorsRefByJoinFilter.put(joinFilter, factorRefBitmap);
  }
}
 
Example 4
Source File: RelMdDistinctRowCount.java    From calcite with Apache License 2.0 6 votes vote down vote up
public Double getDistinctRowCount(Filter rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  // REVIEW zfong 4/18/06 - In the Broadbase code, duplicates are not
  // removed from the two filter lists.  However, the code below is
  // doing so.
  RexNode unionPreds =
      RelMdUtil.unionPreds(
          rel.getCluster().getRexBuilder(),
          predicate,
          rel.getCondition());

  return mq.getDistinctRowCount(rel.getInput(), groupKey, unionPreds);
}
 
Example 5
Source File: IndexConditionInfo.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Given a RexNode corresponding to the condition expression tree and the index descriptor,
 * check if one or more columns involved in the condition tree form a prefix of the columns in the
 * index keys.
 * @param indexDesc
 * @param initCondition
 * @return True if prefix, False if not
 */
public boolean isConditionPrefix(IndexDescriptor indexDesc, RexNode initCondition) {
  List<LogicalExpression> indexCols = indexDesc.getIndexColumns();
  boolean prefix = true;
  int numPrefix = 0;
  if (indexCols.size() > 0 && initCondition != null) {
    int i = 0;
    while (prefix && i < indexCols.size()) {
      LogicalExpression p = indexCols.get(i++);
      List<LogicalExpression> prefixCol = ImmutableList.of(p);
      IndexConditionInfo info = indexConditionRelatedToFields(prefixCol, initCondition);
      if (info != null && info.hasIndexCol) {
        numPrefix++;
        initCondition = info.remainderCondition;
        if (initCondition.isAlwaysTrue()) {
          // all filter conditions are accounted for
          break;
        }
      } else {
        prefix = false;
      }
    }
  }
  return numPrefix > 0;
}
 
Example 6
Source File: ElasticFilterRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private Residue tryWithResidue(RelOptRuleCall call, Residue residue) throws ExpressionNotAnalyzableException, IOException {
  final FilterRelBase filter = call.rel(0);

  final RexBuilder rexBuilder = filter.getCluster().getRexBuilder();
  final RexNode originalCondition = filter.getCondition();

  final RexNode condition = residue.getNewPredicate(originalCondition, rexBuilder);

  final ElasticsearchIntermediatePrel intermediatePrel = call.rel(1);
  final ElasticRuleRelVisitor visitor = new FilterConverterVisitor(rexBuilder, condition, intermediatePrel.getInput()).go();
  final ElasticsearchPrel newInput = visitor.getConvertedTree();
  final ElasticsearchIntermediatePrel newInter = intermediatePrel.withNewInput(newInput);

  final ElasticsearchFilter newFilter = newInter.get(ElasticsearchFilter.class);
  final ElasticIntermediateScanPrel scan = newInter.get(ElasticIntermediateScanPrel.class);

  Residue newResidue = PredicateAnalyzer.analyzeConjunctions(scan, newFilter.getCondition());
  if (newResidue.none()) {
    PredicateAnalyzer.analyze(scan, newFilter.getCondition(), false);

    final RexNode residueCondition = residue.getResidue(originalCondition, rexBuilder);
    if (!residueCondition.isAlwaysTrue()) {
      final Filter residueFilter = filter.copy(filter.getTraitSet(), newInter, residueCondition);
      call.transformTo(residueFilter);
    } else {
      call.transformTo(newInter);
    }
    return Residue.NONE;
  } else {
    RexNode newPredicate = newResidue.getNewPredicate(originalCondition, rexBuilder);
    if (newPredicate.isAlwaysTrue()) {
      throw new ExpressionNotAnalyzableException(String.format("Could not push down any part of condition: %s", filter.getCondition()), null);
    }
    return newResidue;
  }
}
 
Example 7
Source File: RelMdDistinctRowCount.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
public Double getDistinctRowCount(Join rel, RelMetadataQuery mq,
                                  ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  return getDistinctRowCountFromEstimateRowCount(rel, mq, groupKey, predicate);
}
 
Example 8
Source File: IndexPlanUtils.java    From Bats with Apache License 2.0 5 votes vote down vote up
public static RexNode getTotalFilter(RexNode leadColsFilter, RexNode totRemColsFilter, RexBuilder rexBuilder) {
  RexNode condition = leadColsFilter;
  if (leadColsFilter != null && totRemColsFilter != null && !totRemColsFilter.isAlwaysTrue()) {
    List<RexNode> conditions = new ArrayList<RexNode>();
    conditions.add(leadColsFilter);
    conditions.add(totRemColsFilter);
    return RexUtil.composeConjunction(rexBuilder, conditions, true);
  }
  return condition;
}
 
Example 9
Source File: RelOptUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Decomposes a predicate into a list of expressions that are AND'ed
 * together.
 *
 * @param rexPredicate predicate to be analyzed
 * @param rexList      list of decomposed RexNodes
 */
public static void decomposeConjunction(
    RexNode rexPredicate,
    List<RexNode> rexList) {
  if (rexPredicate == null || rexPredicate.isAlwaysTrue()) {
    return;
  }
  if (rexPredicate.isA(SqlKind.AND)) {
    for (RexNode operand : ((RexCall) rexPredicate).getOperands()) {
      decomposeConjunction(operand, rexList);
    }
  } else {
    rexList.add(rexPredicate);
  }
}
 
Example 10
Source File: ApexRelNode.java    From attic-apex-malhar with Apache License 2.0 5 votes vote down vote up
@Override
public RelInfo visit(RelContext context, RelNode node, List<RelInfo> inputStreams)
{
  Join join = (Join)node;
  if (inputStreams.size() != 2) {
    throw new UnsupportedOperationException("Join is a BiRel");
  }

  if ((join.getJoinType() == JoinRelType.FULL) || (join.getJoinType() == JoinRelType.LEFT) ||
      (join.getJoinType() == JoinRelType.RIGHT)) {
    throw new UnsupportedOperationException("Outer joins are not supported");
  }

  final List<Integer> leftKeys = new ArrayList<>();
  final List<Integer> rightKeys = new ArrayList<>();

  RexNode remaining =
      RelOptUtil.splitJoinCondition(join.getLeft(), join.getRight(), join.getCondition(), leftKeys, rightKeys);

  if (leftKeys.size() != rightKeys.size()) {
    throw new RuntimeException("Unexpected condition reached. Left and right condition count should be same");
  }

  if (leftKeys.size() == 0) {
    throw new UnsupportedOperationException("Theta joins are not supported.");
  }

  RelInfo relInfo = addInnerJoinOperator(join, leftKeys, rightKeys, context);

  if (!remaining.isAlwaysTrue()) {
    relInfo = addJoinFilter(join, remaining, relInfo, context);
  }

  return relInfo;
}
 
Example 11
Source File: RelMdUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Returns default estimates for selectivities, in the absence of stats.
 *
 * @param predicate      predicate for which selectivity will be computed;
 *                       null means true, so gives selectity of 1.0
 * @param artificialOnly return only the selectivity contribution from
 *                       artificial nodes
 * @return estimated selectivity
 */
public static double guessSelectivity(
    RexNode predicate,
    boolean artificialOnly) {
  double sel = 1.0;
  if ((predicate == null) || predicate.isAlwaysTrue()) {
    return sel;
  }

  double artificialSel = 1.0;

  for (RexNode pred : RelOptUtil.conjunctions(predicate)) {
    if (pred.getKind() == SqlKind.IS_NOT_NULL) {
      sel *= .9;
    } else if (
        (pred instanceof RexCall)
            && (((RexCall) pred).getOperator()
            == RelMdUtil.ARTIFICIAL_SELECTIVITY_FUNC)) {
      artificialSel *= RelMdUtil.getSelectivityValue(pred);
    } else if (pred.isA(SqlKind.EQUALS)) {
      sel *= .15;
    } else if (pred.isA(SqlKind.COMPARISON)) {
      sel *= .5;
    } else {
      sel *= .25;
    }
  }

  if (artificialOnly) {
    return artificialSel;
  } else {
    return sel * artificialSel;
  }
}
 
Example 12
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 5 votes vote down vote up
private boolean isAlwaysTrue(RexNode predicate) {
  if (predicate instanceof RexCall) {
    RexCall c = (RexCall) predicate;
    if (c.getOperator().getKind() == SqlKind.EQUALS) {
      int lPos = pos(c.getOperands().get(0));
      int rPos = pos(c.getOperands().get(1));
      return lPos != -1 && lPos == rPos;
    }
  }
  return predicate.isAlwaysTrue();
}
 
Example 13
Source File: RelMdUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Returns default estimates for selectivities, in the absence of stats.
 *
 * @param predicate      predicate for which selectivity will be computed;
 *                       null means true, so gives selectity of 1.0
 * @param artificialOnly return only the selectivity contribution from
 *                       artificial nodes
 * @return estimated selectivity
 */
public static double guessSelectivity(
    RexNode predicate,
    boolean artificialOnly) {
  double sel = 1.0;
  if ((predicate == null) || predicate.isAlwaysTrue()) {
    return sel;
  }

  double artificialSel = 1.0;

  for (RexNode pred : RelOptUtil.conjunctions(predicate)) {
    if (pred.getKind() == SqlKind.IS_NOT_NULL) {
      sel *= .9;
    } else if (
        (pred instanceof RexCall)
            && (((RexCall) pred).getOperator()
            == RelMdUtil.ARTIFICIAL_SELECTIVITY_FUNC)) {
      artificialSel *= RelMdUtil.getSelectivityValue(pred);
    } else if (pred.isA(SqlKind.EQUALS)) {
      sel *= .15;
    } else if (pred.isA(SqlKind.COMPARISON)) {
      sel *= .5;
    } else {
      sel *= .25;
    }
  }

  if (artificialOnly) {
    return artificialSel;
  } else {
    return sel * artificialSel;
  }
}
 
Example 14
Source File: JoinUtils.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
   * Check if the given RelNode contains any Cartesian join.
   * Return true if find one. Otherwise, return false.
   *
   * @param relNode     the RelNode to be inspected.
   * @param leftKeys    a list used for the left input into the join which has
   *                    equi-join keys. It can be empty or not (but not null),
   *                    this method will clear this list before using it.
   * @param rightKeys   a list used for the right input into the join which has
   *                    equi-join keys. It can be empty or not (but not null),
   *                    this method will clear this list before using it.
   * @param filterNulls The join key positions for which null values will not
   *                    match.
   * @return            Return true if the given relNode contains Cartesian join.
   *                    Otherwise, return false
   */
public static boolean checkCartesianJoin(RelNode relNode, List<Integer> leftKeys, List<Integer> rightKeys, List<Boolean> filterNulls) {
  if (relNode instanceof Join) {
    leftKeys.clear();
    rightKeys.clear();

    Join joinRel = (Join) relNode;
    RelNode left = joinRel.getLeft();
    RelNode right = joinRel.getRight();

    RexNode remaining = RelOptUtil.splitJoinCondition(left, right, joinRel.getCondition(), leftKeys, rightKeys, filterNulls);
    if (joinRel.getJoinType() == JoinRelType.INNER) {
      if (leftKeys.isEmpty() || rightKeys.isEmpty()) {
        return true;
      }
    } else {
      if (!remaining.isAlwaysTrue() || leftKeys.isEmpty() || rightKeys.isEmpty()) {
        return true;
      }
    }
  }

  for (RelNode child : relNode.getInputs()) {
    if (checkCartesianJoin(child, leftKeys, rightKeys, filterNulls)) {
      return true;
    }
  }

  return false;
}
 
Example 15
Source File: AbstractMaterializedViewRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override
protected RelNode rewriteQuery(RelBuilder relBuilder, RexBuilder rexBuilder, RexSimplify simplify,
        RelMetadataQuery mq, RexNode compensationColumnsEquiPred, RexNode otherCompensationPred,
        Project topProject, RelNode node, BiMap<RelTableRef, RelTableRef> viewToQueryTableMapping,
        EquivalenceClasses viewEC, EquivalenceClasses queryEC) {
    // Our target node is the node below the root, which should have the maximum
    // number of available expressions in the tree in order to maximize our
    // number of rewritings.
    // We create a project on top. If the program is available, we execute
    // it to maximize rewriting opportunities. For instance, a program might
    // pull up all the expressions that are below the aggregate so we can
    // introduce compensation filters easily. This is important depending on
    // the planner strategy.
    RelNode newNode = node;
    RelNode target = node;
    if (unionRewritingPullProgram != null) {
        final HepPlanner tmpPlanner = new HepPlanner(unionRewritingPullProgram);
        tmpPlanner.setRoot(newNode);
        newNode = tmpPlanner.findBestExp();
        target = newNode.getInput(0);
    }

    // All columns required by compensating predicates must be contained
    // in the query.
    List<RexNode> queryExprs = extractReferences(rexBuilder, target);

    if (!compensationColumnsEquiPred.isAlwaysTrue()) {
        compensationColumnsEquiPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs,
                viewToQueryTableMapping.inverse(), queryEC, false, compensationColumnsEquiPred);
        if (compensationColumnsEquiPred == null) {
            // Skip it
            return null;
        }
    }
    // For the rest, we use the query equivalence classes
    if (!otherCompensationPred.isAlwaysTrue()) {
        otherCompensationPred = rewriteExpression(rexBuilder, mq, target, target, queryExprs,
                viewToQueryTableMapping.inverse(), viewEC, true, otherCompensationPred);
        if (otherCompensationPred == null) {
            // Skip it
            return null;
        }
    }
    final RexNode queryCompensationPred = RexUtil.not(RexUtil.composeConjunction(rexBuilder,
            ImmutableList.of(compensationColumnsEquiPred, otherCompensationPred)));

    // Generate query rewriting.
    RelNode rewrittenPlan = relBuilder.push(target)
            .filter(simplify.simplifyUnknownAsFalse(queryCompensationPred)).build();
    if (unionRewritingPullProgram != null) {
        rewrittenPlan = newNode.copy(newNode.getTraitSet(), ImmutableList.of(rewrittenPlan));
    }
    if (topProject != null) {
        return topProject.copy(topProject.getTraitSet(), ImmutableList.of(rewrittenPlan));
    }
    return rewrittenPlan;
}
 
Example 16
Source File: SubstitutionVisitor.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override protected UnifyResult apply(UnifyRuleCall call) {
  final MutableAggregate query = (MutableAggregate) call.query;
  final MutableCalc qInput = (MutableCalc) query.getInput();
  final Pair<RexNode, List<RexNode>> qInputExplained = explainCalc(qInput);
  final RexNode qInputCond = qInputExplained.left;
  final List<RexNode> qInputProjs = qInputExplained.right;

  final MutableAggregate target = (MutableAggregate) call.target;

  final RexBuilder rexBuilder = call.getCluster().getRexBuilder();

  final Mappings.TargetMapping mapping =
      Project.getMapping(fieldCnt(qInput.getInput()), qInputProjs);
  if (mapping == null) {
    return null;
  }

  if (!qInputCond.isAlwaysTrue()) {
    try {
      // Fail the matching when filtering condition references
      // non-grouping columns in target.
      qInputCond.accept(new RexVisitorImpl<Void>(true) {
        @Override public Void visitInputRef(RexInputRef inputRef) {
          if (!target.groupSets.stream()
              .allMatch(groupSet -> groupSet.get(inputRef.getIndex()))) {
            throw Util.FoundOne.NULL;
          }
          return super.visitInputRef(inputRef);
        }
      });
    } catch (Util.FoundOne one) {
      return null;
    }
  }

  final Mapping inverseMapping = mapping.inverse();
  final MutableAggregate aggregate2 =
      permute(query, qInput.getInput(), inverseMapping);

  final Mappings.TargetMapping mappingForQueryCond = Mappings.target(
      target.groupSet::indexOf,
      target.getInput().rowType.getFieldCount(),
      target.groupSet.cardinality());
  final RexNode targetCond = RexUtil.apply(mappingForQueryCond, qInputCond);

  final MutableRel unifiedAggregate =
      unifyAggregates(aggregate2, targetCond, target);
  if (unifiedAggregate == null) {
    return null;
  }
  // Add Project if the mapping breaks order of fields in GroupSet
  if (!Mappings.keepsOrdering(mapping)) {
    final List<Integer> posList = new ArrayList<>();
    final int fieldCount = aggregate2.rowType.getFieldCount();
    final List<Pair<Integer, Integer>> pairs = new ArrayList<>();
    final List<Integer> groupings = aggregate2.groupSet.toList();
    for (int i = 0; i < groupings.size(); i++) {
      pairs.add(Pair.of(mapping.getTarget(groupings.get(i)), i));
    }
    Collections.sort(pairs);
    pairs.forEach(pair -> posList.add(pair.right));
    for (int i = posList.size(); i < fieldCount; i++) {
      posList.add(i);
    }
    final List<RexNode> compenProjs =
        MutableRels.createProjectExprs(unifiedAggregate, posList);
    final RexProgram compensatingRexProgram = RexProgram.create(
        unifiedAggregate.rowType, compenProjs, null,
        query.rowType, rexBuilder);
    final MutableCalc compenCalc =
        MutableCalc.of(unifiedAggregate, compensatingRexProgram);
    if (unifiedAggregate instanceof MutableCalc) {
      final MutableCalc newCompenCalc =
          mergeCalc(rexBuilder, compenCalc, (MutableCalc) unifiedAggregate);
      return tryMergeParentCalcAndGenResult(call, newCompenCalc);
    } else {
      return tryMergeParentCalcAndGenResult(call, compenCalc);
    }
  } else {
    return tryMergeParentCalcAndGenResult(call, unifiedAggregate);
  }
}
 
Example 17
Source File: RelMdUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Computes the number of distinct rows for a set of keys returned from a
 * join. Also known as NDV (number of distinct values).
 *
 * @param joinRel   RelNode representing the join
 * @param joinType  type of join
 * @param groupKey  keys that the distinct row count will be computed for
 * @param predicate join predicate
 * @param useMaxNdv If true use formula <code>max(left NDV, right NDV)</code>,
 *                  otherwise use <code>left NDV * right NDV</code>.
 * @return number of distinct rows
 */
public static Double getJoinDistinctRowCount(RelMetadataQuery mq,
    RelNode joinRel, JoinRelType joinType, ImmutableBitSet groupKey,
    RexNode predicate, boolean useMaxNdv) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  Join join = (Join) joinRel;
  if (join.isSemiJoin()) {
    return getSemiJoinDistinctRowCount(join, mq, groupKey, predicate);
  }
  Double distRowCount;
  ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
  ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
  RelNode left = joinRel.getInputs().get(0);
  RelNode right = joinRel.getInputs().get(1);

  RelMdUtil.setLeftRightBitmaps(
      groupKey,
      leftMask,
      rightMask,
      left.getRowType().getFieldCount());

  // determine which filters apply to the left vs right
  RexNode leftPred = null;
  RexNode rightPred = null;
  if (predicate != null) {
    final List<RexNode> leftFilters = new ArrayList<>();
    final List<RexNode> rightFilters = new ArrayList<>();
    final List<RexNode> joinFilters = new ArrayList<>();
    final List<RexNode> predList = RelOptUtil.conjunctions(predicate);

    RelOptUtil.classifyFilters(
        joinRel,
        predList,
        joinType,
        !joinType.isOuterJoin(),
        !joinType.generatesNullsOnLeft(),
        !joinType.generatesNullsOnRight(),
        joinFilters,
        leftFilters,
        rightFilters);

    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    leftPred =
        RexUtil.composeConjunction(rexBuilder, leftFilters, true);
    rightPred =
        RexUtil.composeConjunction(rexBuilder, rightFilters, true);
  }

  if (useMaxNdv) {
    distRowCount = Math.max(
        mq.getDistinctRowCount(left, leftMask.build(), leftPred),
        mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  } else {
    distRowCount =
      NumberUtil.multiply(
          mq.getDistinctRowCount(left, leftMask.build(), leftPred),
          mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  }

  return RelMdUtil.numDistinctVals(distRowCount, mq.getRowCount(joinRel));
}
 
Example 18
Source File: SubstitutionVisitor.java    From calcite with Apache License 2.0 4 votes vote down vote up
public UnifyResult apply(UnifyRuleCall call) {
  final MutableCalc query = (MutableCalc) call.query;
  final Pair<RexNode, List<RexNode>> queryExplained = explainCalc(query);
  final RexNode queryCond = queryExplained.left;
  final List<RexNode> queryProjs = queryExplained.right;

  final MutableCalc target = (MutableCalc) call.target;
  final Pair<RexNode, List<RexNode>> targetExplained = explainCalc(target);
  final RexNode targetCond = targetExplained.left;
  final List<RexNode> targetProjs = targetExplained.right;

  final RexBuilder rexBuilder = call.getCluster().getRexBuilder();

  try {
    final RexShuttle shuttle = getRexShuttle(targetProjs);
    final RexNode splitted =
        splitFilter(call.getSimplify(), queryCond, targetCond);

    final RexNode compenCond;
    if (splitted != null) {
      if (splitted.isAlwaysTrue()) {
        compenCond = null;
      } else {
        // Compensate the residual filtering condition.
        compenCond = shuttle.apply(splitted);
      }
    } else if (implies(
        call.getCluster(), queryCond, targetCond, query.getInput().rowType)) {
      // Fail to split filtering condition, but implies that target contains
      // all lines of query, thus just set compensating filtering condition
      // as the filtering condition of query.
      compenCond = shuttle.apply(queryCond);
    } else {
      return null;
    }

    final List<RexNode> compenProjs = shuttle.apply(queryProjs);
    if (compenCond == null
        && RexUtil.isIdentity(compenProjs, target.rowType)) {
      return call.result(target);
    } else {
      final RexProgram compenRexProgram = RexProgram.create(
          target.rowType, compenProjs, compenCond,
          query.rowType, rexBuilder);
      final MutableCalc compenCalc = MutableCalc.of(target, compenRexProgram);
      return tryMergeParentCalcAndGenResult(call, compenCalc);
    }
  } catch (MatchFailed e) {
    return null;
  }
}
 
Example 19
Source File: DruidJsonFilter.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * @param rexNode    rexNode to translate to Druid Filter
 * @param rowType    rowType of filter input
 * @param druidQuery Druid query
 *
 * @return Druid Json Filters or null when can not translate to valid Druid Filters.
 */
@Nullable
static DruidJsonFilter toDruidFilters(final RexNode rexNode, RelDataType rowType,
    DruidQuery druidQuery) {
  if (rexNode.isAlwaysTrue()) {
    return JsonExpressionFilter.alwaysTrue();
  }
  if (rexNode.isAlwaysFalse()) {
    return JsonExpressionFilter.alwaysFalse();
  }
  switch (rexNode.getKind()) {
  case IS_TRUE:
  case IS_NOT_FALSE:
    return toDruidFilters(Iterables.getOnlyElement(((RexCall) rexNode).getOperands()), rowType,
        druidQuery);
  case IS_NOT_TRUE:
  case IS_FALSE:
    final DruidJsonFilter simpleFilter = toDruidFilters(Iterables
        .getOnlyElement(((RexCall) rexNode).getOperands()), rowType, druidQuery);
    return simpleFilter != null ? new JsonCompositeFilter(Type.NOT, simpleFilter)
        : simpleFilter;
  case AND:
  case OR:
  case NOT:
    final RexCall call = (RexCall) rexNode;
    final List<DruidJsonFilter> jsonFilters = new ArrayList<>();
    for (final RexNode e : call.getOperands()) {
      final DruidJsonFilter druidFilter = toDruidFilters(e, rowType, druidQuery);
      if (druidFilter == null) {
        return null;
      }
      jsonFilters.add(druidFilter);
    }
    return new JsonCompositeFilter(Type.valueOf(rexNode.getKind().name()),
        jsonFilters);
  }

  final DruidJsonFilter simpleLeafFilter = toSimpleDruidFilter(rexNode, rowType, druidQuery);
  return simpleLeafFilter == null
      ? toDruidExpressionFilter(rexNode, rowType, druidQuery)
      : simpleLeafFilter;
}
 
Example 20
Source File: DrillRelMdSelectivity.java    From Bats with Apache License 2.0 4 votes vote down vote up
private double getScanSelectivityInternal(TableMetadata tableMetadata, RexNode predicate, List<SchemaPath> fieldNames) {
  double sel = 1.0;
  if ((predicate == null) || predicate.isAlwaysTrue()) {
    return sel;
  }
  for (RexNode pred : RelOptUtil.conjunctions(predicate)) {
    double orSel = 0;
    for (RexNode orPred : RelOptUtil.disjunctions(pred)) {
      if (isMultiColumnPredicate(orPred)) {
        orSel += RelMdUtil.guessSelectivity(orPred);  //CALCITE guess
      } else if (orPred.isA(SqlKind.EQUALS)) {
        orSel += computeEqualsSelectivity(tableMetadata, orPred, fieldNames);
      } else if (orPred.isA(RANGE_PREDICATE)) {
        orSel += computeRangeSelectivity(tableMetadata, orPred, fieldNames);
      } else if (orPred.isA(SqlKind.NOT_EQUALS)) {
        orSel += 1.0 - computeEqualsSelectivity(tableMetadata, orPred, fieldNames);
      } else if (orPred.isA(SqlKind.LIKE)) {
        // LIKE selectivity is 5% more than a similar equality predicate, capped at CALCITE guess
        orSel +=  Math.min(computeEqualsSelectivity(tableMetadata, orPred, fieldNames) + LIKE_PREDICATE_SELECTIVITY,
            guessSelectivity(orPred));
      } else if (orPred.isA(SqlKind.NOT)) {
        if (orPred instanceof RexCall) {
          // LIKE selectivity is 5% more than a similar equality predicate, capped at CALCITE guess
          RexNode childOp = ((RexCall) orPred).getOperands().get(0);
          if (childOp.isA(SqlKind.LIKE)) {
            orSel += 1.0 - Math.min(computeEqualsSelectivity(tableMetadata, childOp, fieldNames) + LIKE_PREDICATE_SELECTIVITY,
                    guessSelectivity(childOp));
          } else {
            orSel += 1.0 - guessSelectivity(orPred);
          }
        }
      } else if (orPred.isA(SqlKind.IS_NULL)) {
        orSel += 1.0 - computeIsNotNullSelectivity(tableMetadata, orPred, fieldNames);
      } else if (orPred.isA(SqlKind.IS_NOT_NULL)) {
        orSel += computeIsNotNullSelectivity(tableMetadata, orPred, fieldNames);
      } else {
        // Use the CALCITE guess.
        orSel += guessSelectivity(orPred);
      }
    }
    sel *= orSel;
  }
  // Cap selectivity if it exceeds 1.0
  return (sel > 1.0) ? 1.0 : sel;
}