public void onMatch(RelOptRuleCall call) {
          CalcRel calc = (CalcRel) call.getRels()[0];
          RexProgram program = calc.getProgram();
          final List<RexNode> exprList = program.getExprList();

          // Form a list of expressions with sub-expressions fully
          // expanded.
          final List<RexNode> expandedExprList = new ArrayList<RexNode>(exprList.size());
          final RexShuttle shuttle =
              new RexShuttle() {
                public RexNode visitLocalRef(RexLocalRef localRef) {
                  return expandedExprList.get(localRef.getIndex());
                }
              };
          for (RexNode expr : exprList) {
            expandedExprList.add(expr.accept(shuttle));
          }
          if (reduceExpressions(calc, expandedExprList)) {
            final RexProgramBuilder builder =
                new RexProgramBuilder(
                    calc.getChild().getRowType(), calc.getCluster().getRexBuilder());
            List<RexLocalRef> list = new ArrayList<RexLocalRef>();
            for (RexNode expr : expandedExprList) {
              list.add(builder.registerInput(expr));
            }
            if (program.getCondition() != null) {
              final int conditionIndex = program.getCondition().getIndex();
              final RexNode newConditionExp = expandedExprList.get(conditionIndex);
              if (newConditionExp.isAlwaysTrue()) {
                // condition is always TRUE - drop it
              } else if ((newConditionExp instanceof RexLiteral)
                  || RexUtil.isNullLiteral(newConditionExp, true)) {
                // condition is always NULL or FALSE - replace calc
                // with empty
                call.transformTo(new EmptyRel(calc.getCluster(), calc.getRowType()));
                return;
              } else {
                builder.addCondition(list.get(conditionIndex));
              }
            }
            int k = 0;
            for (RexLocalRef projectExpr : program.getProjectList()) {
              final int index = projectExpr.getIndex();
              builder.addProject(
                  list.get(index).getIndex(),
                  program.getOutputRowType().getFieldList().get(k++).getName());
            }
            call.transformTo(
                new CalcRel(
                    calc.getCluster(),
                    calc.getTraits(),
                    calc.getChild(),
                    calc.getRowType(),
                    builder.getProgram(),
                    calc.getCollationList()));

            // New plan is absolutely better than old plan.
            call.getPlanner().setImportance(calc, 0.0);
          }
        }
Example #2
0
 public void collectVariablesUsed(Set<String> variableSet) {
   final RelOptUtil.VariableUsedVisitor vuv = new RelOptUtil.VariableUsedVisitor();
   for (RexNode expr : program.getExprList()) {
     expr.accept(vuv);
   }
   variableSet.addAll(vuv.variables);
 }
Example #3
0
 public Void visitCall(RexCall call) {
   final RexNode[] operands = call.getOperands();
   for (int i = 0; i < operands.length; i++) {
     RexNode operand = operands[i];
     operand.accept(this);
   }
   return null;
 }
Example #4
0
 /**
  * Applies a visitor to a list of expressions and, if specified, a single expression.
  *
  * @param visitor Visitor
  * @param exprs List of expressions
  * @param expr Single expression, may be null
  */
 public static void apply(RexVisitor<Void> visitor, List<? extends RexNode> exprs, RexNode expr) {
   for (int i = 0; i < exprs.size(); i++) {
     exprs.get(i).accept(visitor);
   }
   if (expr != null) {
     expr.accept(visitor);
   }
 }
Example #5
0
 /**
  * Applies a visitor to an array of expressions and, if specified, a single expression.
  *
  * @param visitor Visitor
  * @param exprs Array of expressions
  * @param expr Single expression, may be null
  */
 public static void apply(RexVisitor<Void> visitor, RexNode[] exprs, RexNode expr) {
   for (int i = 0; i < exprs.length; i++) {
     exprs[i].accept(visitor);
   }
   if (expr != null) {
     expr.accept(visitor);
   }
 }
Example #6
0
 public RexNode visitFieldAccess(RexFieldAccess fieldAccess) {
   final RexNode expr = fieldAccess.getReferenceExpr();
   expr.accept(this);
   final RexNode normalizedExpr = lookup(expr);
   if (normalizedExpr != expr) {
     fieldAccess = new RexFieldAccess(normalizedExpr, fieldAccess.getField());
   }
   return register(fieldAccess);
 }
Example #7
0
 /**
  * Applies a shuttle to an array of expressions. Creates a copy first.
  *
  * @param shuttle Shuttle
  * @param exprs Array of expressions
  */
 public static <T extends RexNode> T[] apply(RexVisitor<T> shuttle, T[] exprs) {
   T[] newExprs = exprs.clone();
   for (int i = 0; i < newExprs.length; i++) {
     final RexNode expr = newExprs[i];
     if (expr != null) {
       newExprs[i] = expr.accept(shuttle);
     }
   }
   return newExprs;
 }
Example #8
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link FilterRel}. */
  public TrimResult trimFields(
      FilterRel filter, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = filter.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RexNode conditionExpr = filter.getCondition();
    final RelNode input = filter.getChild();

    // We use the fields used by the consumer, plus any fields used in the
    // filter.
    BitSet inputFieldsUsed = (BitSet) fieldsUsed.clone();
    final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(inputFieldsUsed, inputExtraFields);
    conditionExpr.accept(inputFinder);

    // Create input with trimmed columns.
    TrimResult trimResult = trimChild(filter, input, inputFieldsUsed, inputExtraFields);
    RelNode newInput = trimResult.left;
    final Mapping inputMapping = trimResult.right;

    // If the input is unchanged, and we need to project all columns,
    // there's nothing we can do.
    if (newInput == input && fieldsUsed.cardinality() == fieldCount) {
      return new TrimResult(filter, Mappings.createIdentity(fieldCount));
    }

    // Build new project expressions, and populate the mapping.
    final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput);
    RexNode newConditionExpr = conditionExpr.accept(shuttle);

    final FilterRel newFilter = new FilterRel(filter.getCluster(), newInput, newConditionExpr);
    assert newFilter.getClass() == filter.getClass();

    // The result has the same mapping as the input gave us. Sometimes we
    // return fields that the consumer didn't ask for, because the filter
    // needs them for its condition.
    return new TrimResult(newFilter, inputMapping);
  }
Example #9
0
 /**
  * Returns whether a given tree contains any {@link org.eigenbase.rex.RexFieldAccess} nodes.
  *
  * @param node a RexNode tree
  */
 public static boolean containsFieldAccess(RexNode node) {
   try {
     RexVisitor<Void> visitor =
         new RexVisitorImpl<Void>(true) {
           public Void visitFieldAccess(RexFieldAccess fieldAccess) {
             throw new Util.FoundOne(fieldAccess);
           }
         };
     node.accept(visitor);
     return false;
   } catch (Util.FoundOne e) {
     Util.swallow(e, null);
     return true;
   }
 }
Example #10
0
 /**
  * Returns whether a given tree contains any {link RexInputRef} nodes.
  *
  * @param node a RexNode tree
  */
 public static boolean containsInputRef(RexNode node) {
   try {
     RexVisitor<Void> visitor =
         new RexVisitorImpl<Void>(true) {
           public Void visitInputRef(RexInputRef inputRef) {
             throw new Util.FoundOne(inputRef);
           }
         };
     node.accept(visitor);
     return false;
   } catch (Util.FoundOne e) {
     Util.swallow(e, null);
     return true;
   }
 }
    public void analyze(RexNode exp) {
      assert (stack.isEmpty());

      exp.accept(this);

      // Deal with top of stack
      assert (stack.size() == 1);
      assert (parentCallTypeStack.isEmpty());
      Constancy rootConstancy = stack.get(0);
      if (rootConstancy == Constancy.REDUCIBLE_CONSTANT) {
        // The entire subtree was constant, so add it to the result.
        addResult(exp);
      }
      stack.clear();
    }
Example #12
0
 public RexNode visitCall(RexCall call) {
   List<RexNode> normalizedOperands = new ArrayList<RexNode>();
   int diffCount = 0;
   for (RexNode operand : call.getOperands()) {
     operand.accept(this);
     final RexNode normalizedOperand = lookup(operand);
     normalizedOperands.add(normalizedOperand);
     if (normalizedOperand != operand) {
       ++diffCount;
     }
   }
   if (diffCount > 0) {
     call = call.clone(call.getType(), normalizedOperands);
   }
   return register(call);
 }
Example #13
0
 /**
  * Returns whether an array of expressions contains a forward reference. That is, if expression #i
  * contains a {@link RexInputRef} referencing field i or greater.
  *
  * @param exprs Array of expressions
  * @param inputRowType Input row type
  * @param fail Whether to assert if there is a forward reference
  * @return Whether there is a forward reference
  */
 public static boolean containForwardRefs(
     RexNode[] exprs, RelDataType inputRowType, boolean fail) {
   final ForwardRefFinder visitor = new ForwardRefFinder(inputRowType);
   for (int i = 0; i < exprs.length; i++) {
     RexNode expr = exprs[i];
     visitor.setLimit(i); // field cannot refer to self or later field
     try {
       expr.accept(visitor);
     } catch (ForwardRefFinder.IllegalForwardRefException e) {
       Util.swallow(e, null);
       assert !fail : "illegal forward reference in " + expr;
       return true;
     }
   }
   return false;
 }
Example #14
0
 /**
  * Returns whether a given node contains a RexCall with a specified operator
  *
  * @param operator to look for
  * @param node a RexNode tree
  */
 public static RexCall findOperatorCall(final SqlOperator operator, RexNode node) {
   try {
     RexVisitor<Void> visitor =
         new RexVisitorImpl<Void>(true) {
           public Void visitCall(RexCall call) {
             if (call.getOperator().equals(operator)) {
               throw new Util.FoundOne(call);
             }
             return super.visitCall(call);
           }
         };
     node.accept(visitor);
     return null;
   } catch (Util.FoundOne e) {
     Util.swallow(e, null);
     return (RexCall) e.getNode();
   }
 }
Example #15
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link JoinRel}. */
  public TrimResult trimFields(JoinRel join, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = join.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RexNode conditionExpr = join.getCondition();
    final int systemFieldCount = join.getSystemFieldList().size();

    // Add in fields used in the condition.
    BitSet fieldsUsedPlus = (BitSet) fieldsUsed.clone();
    final Set<RelDataTypeField> combinedInputExtraFields =
        new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(fieldsUsedPlus, combinedInputExtraFields);
    conditionExpr.accept(inputFinder);

    // If no system fields are used, we can remove them.
    int systemFieldUsedCount = 0;
    for (int i = 0; i < systemFieldCount; ++i) {
      if (fieldsUsed.get(i)) {
        ++systemFieldUsedCount;
      }
    }
    final int newSystemFieldCount;
    if (systemFieldUsedCount == 0) {
      newSystemFieldCount = 0;
    } else {
      newSystemFieldCount = systemFieldCount;
    }

    int offset = systemFieldCount;
    int changeCount = 0;
    int newFieldCount = newSystemFieldCount;
    List<RelNode> newInputs = new ArrayList<RelNode>(2);
    List<Mapping> inputMappings = new ArrayList<Mapping>();
    List<Integer> inputExtraFieldCounts = new ArrayList<Integer>();
    for (RelNode input : join.getInputs()) {
      final RelDataType inputRowType = input.getRowType();
      final int inputFieldCount = inputRowType.getFieldCount();

      // Compute required mapping.
      BitSet inputFieldsUsed = new BitSet(inputFieldCount);
      for (int bit : Util.toIter(fieldsUsedPlus)) {
        if (bit >= offset && bit < offset + inputFieldCount) {
          inputFieldsUsed.set(bit - offset);
        }
      }

      // If there are system fields, we automatically use the
      // corresponding field in each input.
      if (newSystemFieldCount > 0) {
        // calling with newSystemFieldCount == 0 should be safe but hits
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6222207
        inputFieldsUsed.set(0, newSystemFieldCount);
      }

      // FIXME: We ought to collect extra fields for each input
      // individually. For now, we assume that just one input has
      // on-demand fields.
      Set<RelDataTypeField> inputExtraFields =
          input.getRowType().getField("_extra") == null
              ? Collections.<RelDataTypeField>emptySet()
              : combinedInputExtraFields;
      inputExtraFieldCounts.add(inputExtraFields.size());
      TrimResult trimResult = trimChild(join, input, inputFieldsUsed, inputExtraFields);
      newInputs.add(trimResult.left);
      if (trimResult.left != input) {
        ++changeCount;
      }

      final Mapping inputMapping = trimResult.right;
      inputMappings.add(inputMapping);

      // Move offset to point to start of next input.
      offset += inputFieldCount;
      newFieldCount += inputMapping.getTargetCount() + inputExtraFields.size();
    }

    Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, newFieldCount);
    for (int i = 0; i < newSystemFieldCount; ++i) {
      mapping.set(i, i);
    }
    offset = systemFieldCount;
    int newOffset = newSystemFieldCount;
    for (int i = 0; i < inputMappings.size(); i++) {
      Mapping inputMapping = inputMappings.get(i);
      for (IntPair pair : inputMapping) {
        mapping.set(pair.source + offset, pair.target + newOffset);
      }
      offset += inputMapping.getSourceCount();
      newOffset += inputMapping.getTargetCount() + inputExtraFieldCounts.get(i);
    }

    if (changeCount == 0 && mapping.isIdentity()) {
      return new TrimResult(join, Mappings.createIdentity(fieldCount));
    }

    // Build new join.
    final RexVisitor<RexNode> shuttle =
        new RexPermuteInputsShuttle(mapping, newInputs.get(0), newInputs.get(1));
    RexNode newConditionExpr = conditionExpr.accept(shuttle);

    final JoinRel newJoin =
        join.copy(join.getTraitSet(), newConditionExpr, newInputs.get(0), newInputs.get(1));

    return new TrimResult(newJoin, mapping);
  }