/**
   * Determines if a filter condition is a simple one and returns the parameters corresponding to
   * the simple filters.
   *
   * @param calcRel original CalcRel
   * @param filterExprs filter expression being analyzed
   * @param filterList returns the list of filter ordinals in the simple expression
   * @param literals returns the list of literals to be used in the simple comparisons
   * @param op returns the operator to be used in the simple comparison
   * @return true if the filter condition is simple
   */
  private boolean isConditionSimple(
      CalcRel calcRel,
      RexNode filterExprs,
      List<Integer> filterList,
      List<RexLiteral> literals,
      List<CompOperatorEnum> op) {
    SargFactory sargFactory = new SargFactory(calcRel.getCluster().getRexBuilder());
    SargRexAnalyzer rexAnalyzer = sargFactory.newRexAnalyzer(true);
    List<SargBinding> sargBindingList = rexAnalyzer.analyzeAll(filterExprs);

    // Currently, it's all or nothing.  So, if there are filters rejected
    // by the analyzer, we can't process a subset using the reshape
    // exec stream
    if (rexAnalyzer.getNonSargFilterRexNode() != null) {
      return false;
    }

    List<RexInputRef> filterCols = new ArrayList<RexInputRef>();
    List<RexNode> filterOperands = new ArrayList<RexNode>();
    if (FennelRelUtil.extractSimplePredicates(sargBindingList, filterCols, filterOperands, op)) {
      for (RexInputRef filterCol : filterCols) {
        filterList.add(filterCol.getIndex());
      }
      for (RexNode operand : filterOperands) {
        literals.add((RexLiteral) operand);
      }
      return true;
    } else {
      return false;
    }
  }
Пример #2
0
 private List<SqlNode> toSql(RexProgram program, List<RexNode> operandList) {
   final List<SqlNode> list = new ArrayList<SqlNode>();
   for (RexNode rex : operandList) {
     list.add(toSql(program, rex));
   }
   return list;
 }
Пример #3
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link TableFunctionRel}. */
  public TrimResult trimFields(
      TableFunctionRel tabFun, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = tabFun.getRowType();
    final int fieldCount = rowType.getFieldCount();
    List<RelNode> newInputs = new ArrayList<RelNode>();

    for (RelNode input : tabFun.getInputs()) {
      final int inputFieldCount = input.getRowType().getFieldCount();
      BitSet inputFieldsUsed = Util.bitSetBetween(0, inputFieldCount);

      // Create input with trimmed columns.
      final Set<RelDataTypeField> inputExtraFields = Collections.emptySet();
      TrimResult trimResult = trimChildRestore(tabFun, input, inputFieldsUsed, inputExtraFields);
      assert trimResult.right.isIdentity();
      newInputs.add(trimResult.left);
    }

    TableFunctionRel newTabFun = tabFun;
    if (!tabFun.getInputs().equals(newInputs)) {
      newTabFun = tabFun.copy(tabFun.getTraitSet(), newInputs);
    }
    assert newTabFun.getClass() == tabFun.getClass();

    // Always project all fields.
    Mapping mapping = Mappings.createIdentity(fieldCount);
    return new TrimResult(newTabFun, mapping);
  }
Пример #4
0
 public List<SqlMoniker> getAllSchemaObjectNames(List<String> names) {
   List<SqlMoniker> result;
   switch (names.size()) {
     case 0:
       // looking for schema names
       result = new ArrayList<SqlMoniker>();
       for (MockSchema schema : schemas.values()) {
         result.add(new SqlMonikerImpl(schema.name, SqlMonikerType.Schema));
       }
       return result;
     case 1:
       // looking for table names in the given schema
       MockSchema schema = schemas.get(names.get(0));
       if (schema == null) {
         return Collections.emptyList();
       }
       result = new ArrayList<SqlMoniker>();
       for (String tableName : schema.tableNames) {
         result.add(new SqlMonikerImpl(tableName, SqlMonikerType.Table));
       }
       return result;
     default:
       return Collections.emptyList();
   }
 }
    private void analyzeCall(RexCall call, Constancy callConstancy) {
      parentCallTypeStack.add(call.getOperator());

      // visit operands, pushing their states onto stack
      super.visitCall(call);

      // look for NON_CONSTANT operands
      int nOperands = call.getOperands().length;
      List<Constancy> operandStack = stack.subList(stack.size() - nOperands, stack.size());
      for (Constancy operandConstancy : operandStack) {
        if (operandConstancy == Constancy.NON_CONSTANT) {
          callConstancy = Constancy.NON_CONSTANT;
        }
      }

      // Even if all operands are constant, the call itself may
      // be non-deterministic.
      if (!call.getOperator().isDeterministic()) {
        callConstancy = Constancy.NON_CONSTANT;
      } else if (call.getOperator().isDynamicFunction()) {
        // We can reduce the call to a constant, but we can't
        // cache the plan if the function is dynamic
        preparingStmt.disableStatementCaching();
      }

      // Row operator itself can't be reduced to a literal, but if
      // the operands are constants, we still want to reduce those
      if ((callConstancy == Constancy.REDUCIBLE_CONSTANT)
          && (call.getOperator() instanceof SqlRowOperator)) {
        callConstancy = Constancy.NON_CONSTANT;
      }

      if (callConstancy == Constancy.NON_CONSTANT) {
        // any REDUCIBLE_CONSTANT children are now known to be maximal
        // reducible subtrees, so they can be added to the result
        // list
        for (int iOperand = 0; iOperand < nOperands; ++iOperand) {
          Constancy constancy = operandStack.get(iOperand);
          if (constancy == Constancy.REDUCIBLE_CONSTANT) {
            addResult(call.getOperands()[iOperand]);
          }
        }

        // if this cast expression can't be reduced to a literal,
        // then see if we can remove the cast
        if (call.getOperator() == SqlStdOperatorTable.castFunc) {
          reduceCasts(call);
        }
      }

      // pop operands off of the stack
      operandStack.clear();

      // pop this parent call operator off the stack
      parentCallTypeStack.remove(parentCallTypeStack.size() - 1);

      // push constancy result for this call onto stack
      stack.add(callConstancy);
    }
Пример #6
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);
   }
 }
Пример #7
0
 private SqlNode createLeftCall(SqlOperator op, List<SqlNode> nodeList) {
   if (nodeList.size() == 2) {
     return op.createCall(new SqlNodeList(nodeList, POS));
   }
   final List<SqlNode> butLast = Util.skipLast(nodeList);
   final SqlNode last = nodeList.get(nodeList.size() - 1);
   final SqlNode call = createLeftCall(op, butLast);
   return op.createCall(new SqlNodeList(ImmutableList.of(call, last), POS));
 }
Пример #8
0
 /**
  * Applies a mapping to a list of field collations.
  *
  * @param mapping Mapping
  * @param fieldCollations Field collations
  * @return collations with mapping applied
  */
 public static List<RelFieldCollation> apply(
     Mapping mapping, List<RelFieldCollation> fieldCollations) {
   final List<RelFieldCollation> newFieldCollations =
       new ArrayList<RelFieldCollation>(fieldCollations.size());
   for (RelFieldCollation fieldCollation : fieldCollations) {
     newFieldCollations.add(apply(mapping, fieldCollation));
   }
   return newFieldCollations;
 }
Пример #9
0
  /**
   * Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link SetOpRel} (including UNION and
   * UNION ALL).
   */
  public TrimResult trimFields(
      SetOpRel setOp, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = setOp.getRowType();
    final int fieldCount = rowType.getFieldCount();
    int changeCount = 0;

    // Fennel abhors an empty row type, so pretend that the parent rel
    // wants the last field. (The last field is the least likely to be a
    // system field.)
    if (fieldsUsed.isEmpty()) {
      fieldsUsed.set(rowType.getFieldCount() - 1);
    }

    // Compute the desired field mapping. Give the consumer the fields they
    // want, in the order that they appear in the bitset.
    final Mapping mapping = createMapping(fieldsUsed, fieldCount);

    // Create input with trimmed columns.
    final List<RelNode> newInputs = new ArrayList<RelNode>();
    for (RelNode input : setOp.getInputs()) {
      TrimResult trimResult = trimChild(setOp, input, fieldsUsed, extraFields);
      RelNode newInput = trimResult.left;
      final Mapping inputMapping = trimResult.right;

      // We want "mapping", the input gave us "inputMapping", compute
      // "remaining" mapping.
      //    |                   |                |
      //    |---------------- mapping ---------->|
      //    |-- inputMapping -->|                |
      //    |                   |-- remaining -->|
      //
      // For instance, suppose we have columns [a, b, c, d],
      // the consumer asked for mapping = [b, d],
      // and the transformed input has columns inputMapping = [d, a, b].
      // remaining will permute [b, d] to [d, a, b].
      Mapping remaining = Mappings.divide(mapping, inputMapping);

      // Create a projection; does nothing if remaining is identity.
      newInput = CalcRel.projectMapping(newInput, remaining, null);

      if (input != newInput) {
        ++changeCount;
      }
      newInputs.add(newInput);
    }

    // If the input is unchanged, and we need to project all columns,
    // there's to do.
    if (changeCount == 0 && mapping.isIdentity()) {
      return new TrimResult(setOp, mapping);
    }

    RelNode newSetOp = setOp.copy(setOp.getTraitSet(), newInputs);
    return new TrimResult(newSetOp, mapping);
  }
        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);
          }
        }
Пример #11
0
 /** Converts a call to an aggregate function to an expression. */
 public SqlNode toSql(AggregateCall aggCall) {
   SqlOperator op = (SqlAggFunction) aggCall.getAggregation();
   final List<SqlNode> operands = Expressions.list();
   for (int arg : aggCall.getArgList()) {
     operands.add(field(arg));
   }
   return op.createCall(
       aggCall.isDistinct() ? SqlSelectKeyword.DISTINCT.symbol(POS) : null,
       POS,
       operands.toArray(new SqlNode[operands.size()]));
 }
 /** Splits a condition into conjunctions that do or do not intersect with a given bit set. */
 static void split(
     RexNode condition, BitSet bitSet, List<RexNode> intersecting, List<RexNode> nonIntersecting) {
   for (RexNode node : RelOptUtil.conjunctions(condition)) {
     BitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
     if (bitSet.intersects(inputBitSet)) {
       intersecting.add(node);
     } else {
       nonIntersecting.add(node);
     }
   }
 }
Пример #13
0
  /**
   * Creates an OR expression from a list of RexNodes
   *
   * @param rexList list of RexNodes
   * @return OR'd expression
   */
  public static RexNode orRexNodeList(RexBuilder rexBuilder, List<RexNode> rexList) {
    if (rexList.isEmpty()) {
      return null;
    }

    RexNode orExpr = rexList.get(rexList.size() - 1);
    for (int i = rexList.size() - 2; i >= 0; i--) {
      orExpr = rexBuilder.makeCall(SqlStdOperatorTable.orOperator, rexList.get(i), orExpr);
    }
    return orExpr;
  }
Пример #14
0
  public void onMatch(RelOptRuleCall call) {
    JoinRel origJoinRel = (JoinRel) call.rels[0];

    RelNode left = call.rels[1];
    RelNode right = call.rels[2];

    // combine the children MultiJoinRel inputs into an array of inputs
    // for the new MultiJoinRel
    List<BitSet> projFieldsList = new ArrayList<BitSet>();
    List<int[]> joinFieldRefCountsList = new ArrayList<int[]>();
    RelNode[] newInputs =
        combineInputs(origJoinRel, left, right, projFieldsList, joinFieldRefCountsList);

    // combine the outer join information from the left and right
    // inputs, and include the outer join information from the current
    // join, if it's a left/right outer join
    RexNode[] newOuterJoinConds = new RexNode[newInputs.length];
    JoinRelType[] joinTypes = new JoinRelType[newInputs.length];
    combineOuterJoins(origJoinRel, newInputs, left, right, newOuterJoinConds, joinTypes);

    // pull up the join filters from the children MultiJoinRels and
    // combine them with the join filter associated with this JoinRel to
    // form the join filter for the new MultiJoinRel
    RexNode newJoinFilter = combineJoinFilters(origJoinRel, left, right);

    // add on the join field reference counts for the join condition
    // associated with this JoinRel
    Map<Integer, int[]> newJoinFieldRefCountsMap = new HashMap<Integer, int[]>();
    addOnJoinFieldRefCounts(
        newInputs,
        origJoinRel.getRowType().getFieldCount(),
        origJoinRel.getCondition(),
        joinFieldRefCountsList,
        newJoinFieldRefCountsMap);

    RexNode newPostJoinFilter = combinePostJoinFilters(origJoinRel, left, right);

    RelNode multiJoin =
        new MultiJoinRel(
            origJoinRel.getCluster(),
            newInputs,
            newJoinFilter,
            origJoinRel.getRowType(),
            (origJoinRel.getJoinType() == JoinRelType.FULL),
            newOuterJoinConds,
            joinTypes,
            projFieldsList.toArray(new BitSet[projFieldsList.size()]),
            newJoinFieldRefCountsMap,
            newPostJoinFilter);

    call.transformTo(multiJoin);
  }
 /**
  * Locates expressions that can be reduced to literals or converted to expressions with redundant
  * casts removed.
  *
  * @param preparingStmt the statement containing the expressions
  * @param exps list of candidate expressions to be examined for reduction
  * @param constExps returns the list of expressions that can be constant reduced
  * @param addCasts indicator for each expression that can be constant reduced, whether a cast of
  *     the resulting reduced expression is potentially necessary
  * @param removableCasts returns the list of cast expressions where the cast can be removed
  */
 private static void findReducibleExps(
     FarragoSessionPreparingStmt preparingStmt,
     List<RexNode> exps,
     List<RexNode> constExps,
     List<Boolean> addCasts,
     List<RexNode> removableCasts) {
   ReducibleExprLocator gardener =
       new ReducibleExprLocator(preparingStmt, constExps, addCasts, removableCasts);
   for (RexNode exp : exps) {
     gardener.analyze(exp);
   }
   assert (constExps.size() == addCasts.size());
 }
Пример #16
0
  /**
   * Creates an AND expression from a list of RexNodes
   *
   * @param rexList list of RexNodes
   * @return AND'd expression
   */
  public static RexNode andRexNodeList(RexBuilder rexBuilder, List<RexNode> rexList) {
    if (rexList.isEmpty()) {
      return null;
    }

    // create a right-deep tree to allow short-circuiting during
    // expression evaluation
    RexNode andExpr = rexList.get(rexList.size() - 1);
    for (int i = rexList.size() - 2; i >= 0; i--) {
      andExpr = rexBuilder.makeCall(SqlStdOperatorTable.andOperator, rexList.get(i), andExpr);
    }
    return andExpr;
  }
  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);
  }
Пример #18
0
  /**
   * Combines the inputs into a JoinRel into an array of inputs.
   *
   * @param join original join
   * @param left left input into join
   * @param right right input into join
   * @param projFieldsList returns a list of the new combined projection fields
   * @param joinFieldRefCountsList returns a list of the new combined join field reference counts
   * @return combined left and right inputs in an array
   */
  private RelNode[] combineInputs(
      JoinRel join,
      RelNode left,
      RelNode right,
      List<BitSet> projFieldsList,
      List<int[]> joinFieldRefCountsList) {
    // leave the null generating sides of an outer join intact; don't
    // pull up those children inputs into the array we're constructing
    int nInputs;
    int nInputsOnLeft;
    MultiJoinRel leftMultiJoin = null;
    JoinRelType joinType = join.getJoinType();
    boolean combineLeft = canCombine(left, joinType.generatesNullsOnLeft());
    if (combineLeft) {
      leftMultiJoin = (MultiJoinRel) left;
      nInputs = left.getInputs().length;
      nInputsOnLeft = nInputs;
    } else {
      nInputs = 1;
      nInputsOnLeft = 1;
    }
    MultiJoinRel rightMultiJoin = null;
    boolean combineRight = canCombine(right, joinType.generatesNullsOnRight());
    if (combineRight) {
      rightMultiJoin = (MultiJoinRel) right;
      nInputs += right.getInputs().length;
    } else {
      nInputs += 1;
    }

    RelNode[] newInputs = new RelNode[nInputs];
    int i = 0;
    if (combineLeft) {
      for (; i < left.getInputs().length; i++) {
        newInputs[i] = leftMultiJoin.getInput(i);
        projFieldsList.add(((MultiJoinRel) left).getProjFields()[i]);
        joinFieldRefCountsList.add(((MultiJoinRel) left).getJoinFieldRefCountsMap().get(i));
      }
    } else {
      newInputs[0] = left;
      i = 1;
      projFieldsList.add(null);
      joinFieldRefCountsList.add(new int[left.getRowType().getFieldCount()]);
    }
    if (combineRight) {
      for (; i < nInputs; i++) {
        newInputs[i] = rightMultiJoin.getInput(i - nInputsOnLeft);
        projFieldsList.add(((MultiJoinRel) right).getProjFields()[i - nInputsOnLeft]);
        joinFieldRefCountsList.add(
            ((MultiJoinRel) right).getJoinFieldRefCountsMap().get(i - nInputsOnLeft));
      }
    } else {
      newInputs[i] = right;
      projFieldsList.add(null);
      joinFieldRefCountsList.add(new int[right.getRowType().getFieldCount()]);
    }

    return newInputs;
  }
Пример #19
0
  // implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    ProjectRel origProj = call.rel(0);
    JoinRel joinRel = call.rel(1);

    // locate all fields referenced in the projection and join condition;
    // determine which inputs are referenced in the projection and
    // join condition; if all fields are being referenced and there are no
    // special expressions, no point in proceeding any further
    PushProjector pushProject =
        new PushProjector(origProj, joinRel.getCondition(), joinRel, preserveExprCondition);
    if (pushProject.locateAllRefs()) {
      return;
    }

    // create left and right projections, projecting only those
    // fields referenced on each side
    RelNode leftProjRel = pushProject.createProjectRefsAndExprs(joinRel.getLeft(), true, false);
    RelNode rightProjRel = pushProject.createProjectRefsAndExprs(joinRel.getRight(), true, true);

    // convert the join condition to reference the projected columns
    RexNode newJoinFilter = null;
    int[] adjustments = pushProject.getAdjustments();
    if (joinRel.getCondition() != null) {
      List<RelDataTypeField> projJoinFieldList = new ArrayList<RelDataTypeField>();
      projJoinFieldList.addAll(joinRel.getSystemFieldList());
      projJoinFieldList.addAll(leftProjRel.getRowType().getFieldList());
      projJoinFieldList.addAll(rightProjRel.getRowType().getFieldList());
      newJoinFilter =
          pushProject.convertRefsAndExprs(joinRel.getCondition(), projJoinFieldList, adjustments);
    }

    // create a new joinrel with the projected children
    JoinRel newJoinRel =
        new JoinRel(
            joinRel.getCluster(),
            leftProjRel,
            rightProjRel,
            newJoinFilter,
            joinRel.getJoinType(),
            Collections.<String>emptySet(),
            joinRel.isSemiJoinDone(),
            joinRel.getSystemFieldList());

    // put the original project on top of the join, converting it to
    // reference the modified projection list
    ProjectRel topProject = pushProject.createNewProject(newJoinRel, adjustments);

    call.transformTo(topProject);
  }
    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();
    }
Пример #21
0
 public SqlNode field(int ordinal) {
   for (Pair<String, RelDataType> alias : aliases) {
     final List<RelDataTypeField> fields = alias.right.getFieldList();
     if (ordinal < fields.size()) {
       RelDataTypeField field = fields.get(ordinal);
       return new SqlIdentifier(
           !qualified
               ? ImmutableList.of(field.getName())
               : ImmutableList.of(alias.left, field.getName()),
           POS);
     }
     ordinal -= fields.size();
   }
   throw new AssertionError("field ordinal " + ordinal + " out of range " + aliases);
 }
Пример #22
0
 public Prepare.PreparingTable getTable(final List<String> names) {
   switch (names.size()) {
     case 1:
       // assume table in SALES schema (the original default)
       // if it's not supplied, because SqlValidatorTest is effectively
       // using SALES as its default schema.
       return tables.get(ImmutableList.of(defaultCatalog, defaultSchema, names.get(0)));
     case 2:
       return tables.get(ImmutableList.of(defaultCatalog, names.get(0), names.get(1)));
     case 3:
       return tables.get(names);
     default:
       return null;
   }
 }
Пример #23
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);
 }
Пример #24
0
 public RelOptTable getTableForMember(List<String> names) {
   final SqlValidatorTable table = catalogReader.getTable(names);
   final RelDataType rowType = table.getRowType();
   final List<RelCollation> collationList = deduceMonotonicity(table);
   if (names.size() < 3) {
     String[] newNames2 = {"CATALOG", "SALES", ""};
     List<String> newNames = new ArrayList<String>();
     int i = 0;
     while (newNames.size() < newNames2.length) {
       newNames.add(i, newNames2[i]);
       ++i;
     }
     names = newNames;
   }
   return createColumnSet(table, names, rowType, collationList);
 }
        public void onMatch(RelOptRuleCall call) {
          JoinRel join = (JoinRel) call.rels[0];
          List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(join.getChildExps()));
          if (reduceExpressions(join, expList)) {
            call.transformTo(
                new JoinRel(
                    join.getCluster(),
                    join.getLeft(),
                    join.getRight(),
                    expList.get(0),
                    join.getJoinType(),
                    join.getVariablesStopped()));

            // New plan is absolutely better than old plan.
            call.getPlanner().setImportance(join, 0.0);
          }
        }
        public void onMatch(RelOptRuleCall call) {
          ProjectRel project = (ProjectRel) call.rels[0];
          List<RexNode> expList = new ArrayList<RexNode>(Arrays.asList(project.getChildExps()));
          if (reduceExpressions(project, expList)) {
            call.transformTo(
                new ProjectRel(
                    project.getCluster(),
                    project.getChild(),
                    expList.toArray(new RexNode[expList.size()]),
                    project.getRowType(),
                    ProjectRel.Flags.Boxed,
                    Collections.<RelCollation>emptyList()));

            // New plan is absolutely better than old plan.
            call.getPlanner().setImportance(project, 0.0);
          }
        }
 // 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;
 }
  // implement RelOptRule
  public void onMatch(RelOptRuleCall call) {
    CalcRel calcRel = (CalcRel) call.rels[0];
    RexProgram program = calcRel.getProgram();

    // check the projection
    List<Integer> projOrdinals = new ArrayList<Integer>();
    RelDataType outputRowType = isProjectSimple(calcRel, projOrdinals);
    if (outputRowType == null) {
      return;
    }

    RexLocalRef condition = program.getCondition();
    CompOperatorEnum compOp = CompOperatorEnum.COMP_NOOP;
    Integer[] filterOrdinals = {};
    List<RexLiteral> filterLiterals = new ArrayList<RexLiteral>();

    // check the condition
    if (condition != null) {
      RexNode filterExprs = program.expandLocalRef(condition);
      List<Integer> filterList = new ArrayList<Integer>();

      List<CompOperatorEnum> op = new ArrayList<CompOperatorEnum>();
      if (!isConditionSimple(calcRel, filterExprs, filterList, filterLiterals, op)) {
        return;
      }

      compOp = op.get(0);
      filterOrdinals = filterList.toArray(new Integer[filterList.size()]);
    }

    RelNode fennelInput =
        mergeTraitsAndConvert(
            calcRel.getTraits(), FennelRel.FENNEL_EXEC_CONVENTION, calcRel.getChild());
    if (fennelInput == null) {
      return;
    }

    Integer[] projection = projOrdinals.toArray(new Integer[projOrdinals.size()]);
    FennelReshapeRel reshapeRel =
        new FennelReshapeRel(
            calcRel.getCluster(),
            fennelInput,
            projection,
            outputRowType,
            compOp,
            filterOrdinals,
            filterLiterals,
            new FennelRelParamId[] {},
            new Integer[] {},
            null);

    call.transformTo(reshapeRel);
  }
  /**
   * 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);
  }
Пример #30
0
  private static List<RelCollation> deduceMonotonicity(Prepare.PreparingTable table) {
    final List<RelCollation> collationList = new ArrayList<RelCollation>();

    // Deduce which fields the table is sorted on.
    int i = -1;
    for (RelDataTypeField field : table.getRowType().getFieldList()) {
      ++i;
      final SqlMonotonicity monotonicity = table.getMonotonicity(field.getName());
      if (monotonicity != SqlMonotonicity.NotMonotonic) {
        final RelFieldCollation.Direction direction =
            monotonicity.isDecreasing()
                ? RelFieldCollation.Direction.Descending
                : RelFieldCollation.Direction.Ascending;
        collationList.add(
            RelCollationImpl.of(
                new RelFieldCollation(i, direction, RelFieldCollation.NullDirection.UNSPECIFIED)));
      }
    }
    return collationList;
  }