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);
          }
        }
Esempio n. 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);
 }
Esempio n. 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;
 }
Esempio n. 4
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);
 }
Esempio n. 5
0
 /**
  * Creates a key for {@link RexNode} which is the same as another key of another RexNode only if
  * the two have both the same type and textual representation. For example, "10" integer and "10"
  * bigint result in different keys.
  */
 public static String makeKey(RexNode expr) {
   String type = expr.getType().getFullTypeString();
   String separator = ";";
   String node = expr.toString();
   StringBuilder keyBuilder =
       new StringBuilder(type.length() + separator.length() + node.length());
   keyBuilder.append(type).append(separator).append(node);
   return keyBuilder.toString();
 }
Esempio n. 6
0
  private Expression translate0(RexNode expr) {
    if (expr instanceof RexInputRef) {
      // TODO: multiple inputs, e.g. joins
      final Expression input = getInput(0);
      final int index = ((RexInputRef) expr).getIndex();
      final List<RelDataTypeField> fields = program.getInputRowType().getFieldList();
      final RelDataTypeField field = fields.get(index);
      if (fields.size() == 1) {
        return input;
      } else if (input.getType() == Object[].class) {
        return Expressions.convert_(
            Expressions.arrayIndex(input, Expressions.constant(field.getIndex())),
            Types.box(JavaRules.EnumUtil.javaClass(typeFactory, field.getType())));
      } else {
        return Expressions.field(input, field.getName());
      }
    }
    if (expr instanceof RexLocalRef) {
      return translate(program.getExprList().get(((RexLocalRef) expr).getIndex()));
    }
    if (expr instanceof RexLiteral) {
      return Expressions.constant(
          ((RexLiteral) expr).getValue(), typeFactory.getJavaClass(expr.getType()));
    }
    if (expr instanceof RexCall) {
      final RexCall call = (RexCall) expr;
      final SqlOperator operator = call.getOperator();
      final ExpressionType expressionType = SQL_TO_LINQ_OPERATOR_MAP.get(operator);
      if (expressionType != null) {
        switch (operator.getSyntax()) {
          case Binary:
            return Expressions.makeBinary(
                expressionType, translate(call.getOperands()[0]), translate(call.getOperands()[1]));
          case Postfix:
          case Prefix:
            return Expressions.makeUnary(expressionType, translate(call.getOperands()[0]));
          default:
            throw new RuntimeException("unknown syntax " + operator.getSyntax());
        }
      }

      Method method = SQL_OP_TO_JAVA_METHOD_MAP.get(operator);
      if (method != null) {
        List<Expression> exprs = translateList(Arrays.asList(call.operands));
        return !Modifier.isStatic(method.getModifiers())
            ? Expressions.call(exprs.get(0), method, exprs.subList(1, exprs.size()))
            : Expressions.call(method, exprs);
      }

      switch (expr.getKind()) {
        default:
          throw new RuntimeException("cannot translate expression " + expr);
      }
    }
    throw new RuntimeException("cannot translate expression " + expr);
  }
Esempio n. 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;
 }
  public Boolean areColumnsUnique(ProjectRelBase rel, BitSet columns, boolean ignoreNulls) {
    // ProjectRel maps a set of rows to a different set;
    // Without knowledge of the mapping function(whether it
    // preserves uniqueness), it is only safe to derive uniqueness
    // info from the child of a project when the mapping is f(a) => a.
    //
    // Also need to map the input column set to the corresponding child
    // references

    List<RexNode> projExprs = rel.getProjects();
    BitSet childColumns = new BitSet();
    for (int bit : BitSets.toIter(columns)) {
      RexNode projExpr = projExprs.get(bit);
      if (projExpr instanceof RexInputRef) {
        childColumns.set(((RexInputRef) projExpr).getIndex());
      } else if (projExpr instanceof RexCall && ignoreNulls) {
        // If the expression is a cast such that the types are the same
        // except for the nullability, then if we're ignoring nulls,
        // it doesn't matter whether the underlying column reference
        // is nullable.  Check that the types are the same by making a
        // nullable copy of both types and then comparing them.
        RexCall call = (RexCall) projExpr;
        if (call.getOperator() != SqlStdOperatorTable.CAST) {
          continue;
        }
        RexNode castOperand = call.getOperands().get(0);
        if (!(castOperand instanceof RexInputRef)) {
          continue;
        }
        RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
        RelDataType castType = typeFactory.createTypeWithNullability(projExpr.getType(), true);
        RelDataType origType = typeFactory.createTypeWithNullability(castOperand.getType(), true);
        if (castType.equals(origType)) {
          childColumns.set(((RexInputRef) castOperand).getIndex());
        }
      } else {
        // If the expression will not influence uniqueness of the
        // projection, then skip it.
        continue;
      }
    }

    // If no columns can affect uniqueness, then return unknown
    if (childColumns.cardinality() == 0) {
      return null;
    }

    return RelMetadataQuery.areColumnsUnique(rel.getChild(), childColumns, ignoreNulls);
  }
Esempio n. 9
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;
 }
Esempio n. 10
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);
 }
    private void addResult(RexNode exp) {
      // Cast of literal can't be reduced, so skip those (otherwise we'd
      // go into an infinite loop as we add them back).
      if (exp.getKind() == RexKind.Cast) {
        RexCall cast = (RexCall) exp;
        RexNode operand = cast.getOperands()[0];
        if (operand instanceof RexLiteral) {
          return;
        }
      }
      constExprs.add(exp);

      // In the case where the expression corresponds to a UDR argument,
      // we need to preserve casts.  Note that this only applies to
      // the topmost argument, not expressions nested within the UDR
      // call.
      //
      // REVIEW zfong 6/13/08 - Are there other expressions where we
      // also need to preserve casts?
      if (parentCallTypeStack.isEmpty()) {
        addCasts.add(false);
      } else {
        addCasts.add(
            parentCallTypeStack.get(parentCallTypeStack.size() - 1)
                instanceof FarragoUserDefinedRoutine);
      }
    }
Esempio n. 12
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);
   }
 }
Esempio n. 13
0
 protected RexNode register(RexNode expr) {
   final String key = expr.toString();
   final RexNode previous = mapDigestToExpr.put(key, expr);
   if (!allowDups && (previous != null)) {
     throw new SubExprExistsException(expr);
   }
   return expr;
 }
Esempio n. 14
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);
   }
 }
 // override RexShuttle
 public RexNode visitCall(final RexCall call) {
   int i = reducibleExps.indexOf(call);
   if (i == -1) {
     return super.visitCall(call);
   }
   RexNode replacement = reducedValues.get(i);
   if (addCasts.get(i) && (replacement.getType() != call.getType())) {
     // Handle change from nullable to NOT NULL by claiming
     // that the result is still nullable, even though
     // we know it isn't.
     //
     // Also, we cannot reduce CAST('abc' AS VARCHAR(4)) to 'abc'.
     // If we make 'abc' of type VARCHAR(4), we may later encounter
     // the same expression in a ProjectRel's digest where it has
     // type VARCHAR(3), and that's wrong.
     replacement = rexBuilder.makeCast(call.getType(), replacement);
   }
   return replacement;
 }
  /**
   * Determines if a projection is simple.
   *
   * @param calcRel CalcRel containing the projection
   * @param projOrdinals if the projection is simple, returns the ordinals of the projection inputs
   * @return rowtype corresponding to the projection, provided it is simple; otherwise null is
   *     returned
   */
  private RelDataType isProjectSimple(CalcRel calcRel, List<Integer> projOrdinals) {
    // Loop through projection expressions.  If we find a non-simple
    // projection expression, simply return.
    RexProgram program = calcRel.getProgram();
    List<RexLocalRef> projList = program.getProjectList();
    int nProjExprs = projList.size();
    RelDataType[] types = new RelDataType[nProjExprs];
    String[] fieldNames = new String[nProjExprs];
    RelDataTypeField[] projFields = calcRel.getRowType().getFields();

    for (int i = 0; i < nProjExprs; i++) {
      RexNode projExpr = program.expandLocalRef(projList.get(i));
      if (projExpr instanceof RexInputRef) {
        projOrdinals.add(((RexInputRef) projExpr).getIndex());
        types[i] = projExpr.getType();
        fieldNames[i] = projFields[i].getName();
        continue;
      } else if (!(projExpr instanceof RexCall)) {
        return null;
      }

      RexCall rexCall = (RexCall) projExpr;
      if (rexCall.getOperator() != SqlStdOperatorTable.castFunc) {
        return null;
      }
      RexNode castOperand = rexCall.getOperands()[0];
      if (!(castOperand instanceof RexInputRef)) {
        return null;
      }
      RelDataType castType = projExpr.getType();
      RelDataType origType = castOperand.getType();
      if (isCastSimple(origType, castType)) {
        projOrdinals.add(((RexInputRef) castOperand).getIndex());
        types[i] = castType;
        fieldNames[i] = projFields[i].getName();
      } else {
        return null;
      }
    }

    // return the rowtype corresponding to the output of the projection
    return calcRel.getCluster().getTypeFactory().createStructType(types, fieldNames);
  }
        public void onMatch(RelOptRuleCall call) {
          FilterRel filter = (FilterRel) call.rels[0];
          List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(filter.getChildExps()));
          RexNode newConditionExp;
          boolean reduced;
          if (reduceExpressions(filter, expList)) {
            assert (expList.size() == 1);
            newConditionExp = expList.get(0);
            reduced = true;
          } else {
            // No reduction, but let's still test the original
            // predicate to see if it was already a constant,
            // in which case we don't need any runtime decision
            // about filtering.
            newConditionExp = filter.getChildExps()[0];
            reduced = false;
          }
          if (newConditionExp.isAlwaysTrue()) {
            call.transformTo(filter.getChild());
          } else if ((newConditionExp instanceof RexLiteral)
              || RexUtil.isNullLiteral(newConditionExp, true)) {
            call.transformTo(new EmptyRel(filter.getCluster(), filter.getRowType()));
          } else if (reduced) {
            call.transformTo(CalcRel.createFilter(filter.getChild(), expList.get(0)));
          } else {
            if (newConditionExp instanceof RexCall) {
              RexCall rexCall = (RexCall) newConditionExp;
              boolean reverse = (rexCall.getOperator() == SqlStdOperatorTable.notOperator);
              if (reverse) {
                rexCall = (RexCall) rexCall.getOperands()[0];
              }
              reduceNotNullableFilter(call, filter, rexCall, reverse);
            }
            return;
          }

          // New plan is absolutely better than old plan.
          call.getPlanner().setImportance(filter, 0.0);
        }
Esempio n. 18
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);
  }
    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();
    }
Esempio n. 20
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;
   }
 }
Esempio n. 21
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;
   }
 }
Esempio n. 22
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();
   }
 }
Esempio n. 23
0
  /**
   * Shifts a filter originating from the right child of the JoinRel to the right, to reflect the
   * filter now being applied on the resulting MultiJoinRel.
   *
   * @param joinRel the original JoinRel
   * @param left the left child of the JoinRel
   * @param right the right child of the JoinRel
   * @param rightFilter the filter originating from the right child
   * @return the adjusted right filter
   */
  private RexNode shiftRightFilter(
      JoinRel joinRel, RelNode left, MultiJoinRel right, RexNode rightFilter) {
    if (rightFilter == null) {
      return null;
    }

    int nFieldsOnLeft = left.getRowType().getFields().length;
    int nFieldsOnRight = right.getRowType().getFields().length;
    int[] adjustments = new int[nFieldsOnRight];
    for (int i = 0; i < nFieldsOnRight; i++) {
      adjustments[i] = nFieldsOnLeft;
    }
    rightFilter =
        rightFilter.accept(
            new RelOptUtil.RexInputConverter(
                joinRel.getCluster().getRexBuilder(),
                right.getRowType().getFields(),
                joinRel.getRowType().getFields(),
                adjustments));
    return rightFilter;
  }
Esempio n. 24
0
 /**
  * Returns whether a node represents the NULL value.
  *
  * <p>Examples:
  *
  * <ul>
  *   <li>For {@link org.eigenbase.rex.RexLiteral} Unknown, returns false.
  *   <li>For <code>CAST(NULL AS <i>type</i>)</code>, returns true if <code>
  * allowCast</code> is true, false otherwise.
  *   <li>For <code>CAST(CAST(NULL AS <i>type</i>) AS <i>type</i>))</code>, returns false.
  * </ul>
  */
 public static boolean isNullLiteral(RexNode node, boolean allowCast) {
   if (node instanceof RexLiteral) {
     RexLiteral literal = (RexLiteral) node;
     if (literal.getTypeName() == SqlTypeName.NULL) {
       assert (null == literal.getValue());
       return true;
     } else {
       // We don't regard UNKNOWN -- SqlLiteral(null,Boolean) -- as
       // NULL.
       return false;
     }
   }
   if (allowCast) {
     if (node.isA(RexKind.Cast)) {
       RexCall call = (RexCall) node;
       if (isNullLiteral(call.operands[0], false)) {
         // node is "CAST(NULL as type)"
         return true;
       }
     }
   }
   return false;
 }
Esempio n. 25
0
  /**
   * Adds on to the existing join condition reference counts the references from the new join
   * condition.
   *
   * @param multiJoinInputs inputs into the new MultiJoinRel
   * @param nTotalFields total number of fields in the MultiJoinRel
   * @param joinCondition the new join condition
   * @param origJoinFieldRefCounts existing join condition reference counts
   * @param newJoinFieldRefCountsMap map containing the new join condition reference counts, indexed
   *     by input #
   */
  private void addOnJoinFieldRefCounts(
      RelNode[] multiJoinInputs,
      int nTotalFields,
      RexNode joinCondition,
      List<int[]> origJoinFieldRefCounts,
      Map<Integer, int[]> newJoinFieldRefCountsMap) {
    // count the input references in the join condition
    int[] joinCondRefCounts = new int[nTotalFields];
    joinCondition.accept(new InputReferenceCounter(joinCondRefCounts));

    // first, make a copy of the ref counters
    int nInputs = multiJoinInputs.length;
    int currInput = 0;
    for (int[] origRefCounts : origJoinFieldRefCounts) {
      newJoinFieldRefCountsMap.put(currInput, (int[]) origRefCounts.clone());
      currInput++;
    }

    // add on to the counts for each input into the MultiJoinRel the
    // reference counts computed for the current join condition
    currInput = -1;
    int startField = 0;
    int nFields = 0;
    for (int i = 0; i < nTotalFields; i++) {
      if (joinCondRefCounts[i] == 0) {
        continue;
      }
      while (i >= (startField + nFields)) {
        startField += nFields;
        currInput++;
        assert (currInput < nInputs);
        nFields = multiJoinInputs[currInput].getRowType().getFieldCount();
      }
      int[] refCounts = newJoinFieldRefCountsMap.get(currInput);
      refCounts[i - startField] += joinCondRefCounts[i];
    }
  }
Esempio n. 26
0
  /**
   * Analyzes a rex predicate.
   *
   * @param rexPredicate predicate to be analyzed
   * @return corresponding bound sarg expression, or null if analysis failed
   */
  public SargBinding analyze(RexNode rexPredicate) {
    NodeVisitor visitor = new NodeVisitor();

    // Initialize analysis state.
    exprStack = new ArrayList<SargExpr>();
    failed = false;
    boundInputRef = null;
    clearLeaf();

    // Walk the predicate.
    rexPredicate.accept(visitor);

    if (boundInputRef == null) {
      // No variable references at all, so not sargable.
      failed = true;
    }

    if (exprStack.isEmpty()) {
      failed = true;
    }

    if (failed) {
      return null;
    }

    // well-formedness assumption
    assert (exprStack.size() == 1);

    SargExpr expr = exprStack.get(0);

    if (!testDynamicParamSupport(expr)) {
      failed = true;
      return null;
    }

    return new SargBinding(expr, boundInputRef);
  }
Esempio n. 27
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);
  }
Esempio n. 28
0
 /**
  * Returns whether a node represents the NULL value or a series of nested CAST(NULL as <TYPE>)
  * calls<br>
  * For Example:<br>
  * isNull(CAST(CAST(NULL as INTEGER) AS VARCHAR(1))) returns true
  */
 public static boolean isNull(RexNode node) {
   /* Checks to see if the RexNode is null */
   return RexLiteral.isNullLiteral(node)
       || ((node.getKind() == RexKind.Cast) && isNull(((RexCall) node).operands[0]));
 }
Esempio n. 29
0
 protected RexNode lookup(RexNode expr) {
   return mapDigestToExpr.get(expr.toString());
 }
Esempio n. 30
0
 /**
  * Returns a guess for the selectivity of an expression.
  *
  * @param exp expression of interest, or null for none (implying a selectivity of 1.0)
  * @return guessed selectivity
  */
 public static double getSelectivity(RexNode exp) {
   if ((exp == null) || exp.isAlwaysTrue()) {
     return 1;
   }
   return 0.1;
 }