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);
          }
        }
예제 #2
0
파일: RexUtil.java 프로젝트: kunlqt/optiq
  /**
   * 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;
  }
예제 #3
0
파일: RexUtil.java 프로젝트: kunlqt/optiq
  /**
   * 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;
  }
예제 #4
0
 /**
  * Creates a relational expression which permutes the output fields of a relational expression
  * according to a permutation.
  *
  * <p>Optimizations:
  *
  * <ul>
  *   <li>If the relational expression is a {@link CalcRel} or {@link ProjectRel} which is already
  *       acting as a permutation, combines the new permutation with the old;
  *   <li>If the permutation is the identity, returns the original relational expression.
  * </ul>
  *
  * <p>If a permutation is combined with its inverse, these optimizations would combine to remove
  * them both.
  *
  * @param rel Relational expression
  * @param permutation Permutation to apply to fields
  * @param fieldNames Field names; if null, or if a particular entry is null, the name of the
  *     permuted field is used
  * @return relational expression which permutes its input fields
  */
 public static RelNode permute(RelNode rel, Permutation permutation, List<String> fieldNames) {
   if (permutation.isIdentity()) {
     return rel;
   }
   if (rel instanceof CalcRel) {
     CalcRel calcRel = (CalcRel) rel;
     Permutation permutation1 = calcRel.getProgram().getPermutation();
     if (permutation1 != null) {
       Permutation permutation2 = permutation.product(permutation1);
       return permute(rel, permutation2, null);
     }
   }
   if (rel instanceof ProjectRel) {
     Permutation permutation1 = ((ProjectRel) rel).getPermutation();
     if (permutation1 != null) {
       Permutation permutation2 = permutation.product(permutation1);
       return permute(rel, permutation2, null);
     }
   }
   final List<RelDataType> outputTypeList = new ArrayList<RelDataType>();
   final List<String> outputNameList = new ArrayList<String>();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<RexLocalRef> projectRefList = new ArrayList<RexLocalRef>();
   final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
   for (int i = 0; i < permutation.getTargetCount(); i++) {
     int target = permutation.getTarget(i);
     final RelDataTypeField targetField = fields.get(target);
     outputTypeList.add(targetField.getType());
     outputNameList.add(
         ((fieldNames == null) || (fieldNames.size() <= i) || (fieldNames.get(i) == null))
             ? targetField.getName()
             : fieldNames.get(i));
     exprList.add(rel.getCluster().getRexBuilder().makeInputRef(fields.get(i).getType(), i));
     final int source = permutation.getSource(i);
     projectRefList.add(new RexLocalRef(source, fields.get(source).getType()));
   }
   final RexProgram program =
       new RexProgram(
           rel.getRowType(),
           exprList,
           projectRefList,
           null,
           rel.getCluster().getTypeFactory().createStructType(outputTypeList, outputNameList));
   return new CalcRel(
       rel.getCluster(),
       rel.getTraitSet(),
       rel,
       program.getOutputRowType(),
       program,
       Collections.<RelCollation>emptyList());
 }
예제 #5
0
파일: CalcRel.java 프로젝트: vlsi/optiq
 /**
  * Creates a relational expression which projects an array of expressions, and optionally
  * optimizes.
  *
  * <p>The result may not be a {@link ProjectRel}. If the projection is trivial, <code>child</code>
  * is returned directly; and future versions may return other formulations of expressions, such as
  * {@link CalcRel}.
  *
  * @param child input relational expression
  * @param exprs list of expressions for the input columns
  * @param fieldNames aliases of the expressions, or null to generate
  * @param optimize Whether to return <code>child</code> unchanged if the projections are trivial.
  */
 public static RelNode createProject(
     RelNode child, List<RexNode> exprs, List<String> fieldNames, boolean optimize) {
   final RelOptCluster cluster = child.getCluster();
   final RexProgram program =
       RexProgram.create(child.getRowType(), exprs, null, fieldNames, cluster.getRexBuilder());
   final List<RelCollation> collationList = program.getCollations(child.getCollationList());
   if (DEPRECATE_PROJECT_AND_FILTER) {
     return new CalcRel(
         cluster, child.getTraitSet(), child, program.getOutputRowType(), program, collationList);
   } else {
     final RelDataType rowType =
         RexUtil.createStructType(
             cluster.getTypeFactory(),
             exprs,
             fieldNames == null
                 ? null
                 : SqlValidatorUtil.uniquify(fieldNames, SqlValidatorUtil.F_SUGGESTER));
     if (optimize && RemoveTrivialProjectRule.isIdentity(exprs, rowType, child.getRowType())) {
       return child;
     }
     return new ProjectRel(
         cluster,
         cluster.traitSetOf(
             collationList.isEmpty() ? RelCollationImpl.EMPTY : collationList.get(0)),
         child,
         exprs,
         rowType,
         ProjectRelBase.Flags.BOXED);
   }
 }
    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);
      }
    }
예제 #7
0
 /**
  * Creates a relational expression which projects an array of expressions, and optionally
  * optimizes.
  *
  * <p>The result may not be a {@link ProjectRel}. If the projection is trivial, <code>child</code>
  * is returned directly; and future versions may return other formulations of expressions, such as
  * {@link CalcRel}.
  *
  * @param child input relational expression
  * @param exprs list of expressions for the input columns
  * @param fieldNames aliases of the expressions, or null to generate
  * @param optimize Whether to return <code>child</code> unchanged if the projections are trivial.
  */
 public static RelNode createProject(
     RelNode child, List<RexNode> exprs, List<String> fieldNames, boolean optimize) {
   final RelOptCluster cluster = child.getCluster();
   final RexProgram program =
       RexProgram.create(child.getRowType(), exprs, null, fieldNames, cluster.getRexBuilder());
   final List<RelCollation> collationList = program.getCollations(child.getCollationList());
   if (DeprecateProjectAndFilter) {
     return new CalcRel(
         cluster, child.getTraitSet(), child, program.getOutputRowType(), program, collationList);
   } else {
     final RelDataType rowType =
         RexUtil.createStructType(cluster.getTypeFactory(), exprs, fieldNames);
     if (optimize && RemoveTrivialProjectRule.isIdentity(exprs, rowType, child.getRowType())) {
       return child;
     }
     return new ProjectRel(
         cluster,
         cluster.traitSetOf(
             collationList.isEmpty() ? RelCollationImpl.EMPTY : collationList.get(0)),
         child,
         exprs,
         rowType,
         ProjectRelBase.Flags.Boxed);
   }
 }
    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);
    }
예제 #9
0
파일: RexUtil.java 프로젝트: kunlqt/optiq
 /**
  * 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);
   }
 }
 // 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;
 }
 public static Mapping source(List<Integer> targets, int targetCount) {
   final int sourceCount = targets.size();
   final PartialFunctionImpl mapping =
       new PartialFunctionImpl(sourceCount, targetCount, MappingType.FUNCTION);
   for (int source = 0; source < sourceCount; source++) {
     int target = targets.get(source);
     mapping.set(source, target);
   }
   return mapping;
 }
 public static Mapping target(List<Integer> sources, int sourceCount) {
   final int targetCount = sources.size();
   final PartialFunctionImpl mapping =
       new PartialFunctionImpl(sourceCount, targetCount, MappingType.FUNCTION);
   for (int target = 0; target < targetCount; target++) {
     int source = sources.get(target);
     mapping.set(source, target);
   }
   return mapping;
 }
 /** Returns whether a list of integers is the identity mapping [0, ..., n - 1]. */
 public static boolean isIdentity(List<Integer> list, int count) {
   if (list.size() != count) {
     return false;
   }
   for (int i = 0; i < count; i++) {
     final Integer o = list.get(i);
     if (o == null || o != i) {
       return false;
     }
   }
   return true;
 }
예제 #14
0
 /**
  * Creates a relational expression which projects the output fields of a relational expression
  * according to a partial mapping.
  *
  * <p>A partial mapping is weaker than a permutation: every target has one source, but a source
  * may have 0, 1 or more than one targets. Usually the result will have fewer fields than the
  * source, unless some source fields are projected multiple times.
  *
  * <p>This method could optimize the result as {@link #permute} does, but does not at present.
  *
  * @param rel Relational expression
  * @param mapping Mapping from source fields to target fields. The mapping type must obey the
  *     constaints {@link MappingType#isMandatorySource()} and {@link
  *     MappingType#isSingleSource()}, as does {@link MappingType#InverseFunction}.
  * @param fieldNames Field names; if null, or if a particular entry is null, the name of the
  *     permuted field is used
  * @return relational expression which projects a subset of the input fields
  */
 public static RelNode projectMapping(RelNode rel, Mapping mapping, List<String> fieldNames) {
   assert mapping.getMappingType().isSingleSource();
   assert mapping.getMappingType().isMandatorySource();
   if (mapping.isIdentity()) {
     return rel;
   }
   final List<RelDataType> outputTypeList = new ArrayList<RelDataType>();
   final List<String> outputNameList = new ArrayList<String>();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<RexLocalRef> projectRefList = new ArrayList<RexLocalRef>();
   final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
   for (int i = 0; i < fields.size(); i++) {
     final RelDataTypeField field = fields.get(i);
     exprList.add(rel.getCluster().getRexBuilder().makeInputRef(field.getType(), i));
   }
   for (int i = 0; i < mapping.getTargetCount(); i++) {
     int source = mapping.getSource(i);
     final RelDataTypeField sourceField = fields.get(source);
     outputTypeList.add(sourceField.getType());
     outputNameList.add(
         ((fieldNames == null) || (fieldNames.size() <= i) || (fieldNames.get(i) == null))
             ? sourceField.getName()
             : fieldNames.get(i));
     projectRefList.add(new RexLocalRef(source, sourceField.getType()));
   }
   final RexProgram program =
       new RexProgram(
           rel.getRowType(),
           exprList,
           projectRefList,
           null,
           rel.getCluster().getTypeFactory().createStructType(outputTypeList, outputNameList));
   return new CalcRel(
       rel.getCluster(),
       rel.getTraitSet(),
       rel,
       program.getOutputRowType(),
       program,
       Collections.<RelCollation>emptyList());
 }
        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);
        }
예제 #16
0
 /**
  * Resolves a multi-part identifier such as "SCHEMA.EMP.EMPNO" to a namespace. The returned
  * namespace may represent a schema, table, column, etc.
  *
  * @pre names.size() > 0
  * @post return != null
  */
 public static SqlValidatorNamespace lookup(SqlValidatorScope scope, List<String> names) {
   Util.pre(names.size() > 0, "names.size() > 0");
   SqlValidatorNamespace namespace = null;
   for (int i = 0; i < names.size(); i++) {
     String name = names.get(i);
     if (i == 0) {
       namespace = scope.resolve(name, null, null);
     } else {
       namespace = namespace.lookupChild(name);
     }
   }
   Util.permAssert(namespace != null, "post: namespace != null");
   return namespace;
 }
    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();
    }
예제 #18
0
  public void onMatch(RelOptRuleCall call) {
    assert matches(call);
    final JoinRel join = (JoinRel) call.rels[0];
    final List<Integer> leftKeys = new ArrayList<Integer>();
    final List<Integer> rightKeys = new ArrayList<Integer>();
    RelNode right = join.getRight();
    final RelNode left = join.getLeft();
    RexNode remainingCondition =
        RelOptUtil.splitJoinCondition(left, right, join.getCondition(), leftKeys, rightKeys);
    assert leftKeys.size() == rightKeys.size();
    final List<CorrelatorRel.Correlation> correlationList =
        new ArrayList<CorrelatorRel.Correlation>();
    if (leftKeys.size() > 0) {
      final RelOptCluster cluster = join.getCluster();
      final RexBuilder rexBuilder = cluster.getRexBuilder();
      int k = 0;
      RexNode condition = null;
      for (Integer leftKey : leftKeys) {
        Integer rightKey = rightKeys.get(k++);
        final String dyn_inIdStr = cluster.getQuery().createCorrel();
        final int dyn_inId = RelOptQuery.getCorrelOrdinal(dyn_inIdStr);

        // Create correlation to say 'each row, set variable #id
        // to the value of column #leftKey'.
        correlationList.add(new CorrelatorRel.Correlation(dyn_inId, leftKey));
        condition =
            RelOptUtil.andJoinFilters(
                rexBuilder,
                condition,
                rexBuilder.makeCall(
                    SqlStdOperatorTable.equalsOperator,
                    rexBuilder.makeInputRef(
                        right.getRowType().getFieldList().get(rightKey).getType(), rightKey),
                    rexBuilder.makeCorrel(
                        left.getRowType().getFieldList().get(leftKey).getType(), dyn_inIdStr)));
      }
      right = CalcRel.createFilter(right, condition);
    }
    RelNode newRel =
        new CorrelatorRel(
            join.getCluster(),
            left,
            right,
            remainingCondition,
            correlationList,
            join.getJoinType());
    call.transformTo(newRel);
  }
        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);
          }
        }
 /**
  * Applies a mapping to a list.
  *
  * @param mapping Mapping
  * @param list List
  * @param <T> Element type
  * @return List with elements permuted according to mapping
  */
 public static <T> List<T> apply(final Mapping mapping, final List<T> list) {
   if (mapping.getSourceCount() != list.size()) {
     // REVIEW: too strict?
     throw new IllegalArgumentException(
         "mapping source count "
             + mapping.getSourceCount()
             + " does not match list size "
             + list.size());
   }
   final int targetCount = mapping.getTargetCount();
   final List<T> list2 = new ArrayList<T>(targetCount);
   for (int target = 0; target < targetCount; ++target) {
     final int source = mapping.getSource(target);
     list2.add(list.get(source));
   }
   return list2;
 }
예제 #21
0
  // implement SargExpr
  public SargIntervalSequence evaluate() {
    if (setOp == SargSetOperator.COMPLEMENT) {
      assert (children.size() == 1);
      SargExpr child = children.get(0);
      return child.evaluateComplemented();
    }

    List<SargIntervalSequence> list = evaluateChildren(this);

    switch (setOp) {
      case UNION:
        return evaluateUnion(list);
      case INTERSECTION:
        return evaluateIntersection(list);
      default:
        throw Util.newInternal(setOp.toString());
    }
  }
 /**
  * Creates a partial mapping from a list. For example, <code>
  * PartialMapping({1, 2, 4}, 6)</code> creates the mapping
  *
  * <table border="1">
  * <caption>Example</caption>
  * <tr>
  * <th>source</th>
  * <td>0</td>
  * <td>1</td>
  * <td>2</td>
  * <td>3</td>
  * <td>4</td>
  * <td>5</td>
  * </tr>
  * <tr>
  * <th>target</th>
  * <td>-1</td>
  * <td>0</td>
  * <td>1</td>
  * <td>-1</td>
  * <td>2</td>
  * <td>-1</td>
  * </tr>
  * </table>
  *
  * @param sourceList List whose i'th element is the source of target #i
  * @param sourceCount Number of elements in the source domain
  * @param mappingType Mapping type, must be {@link
  *     org.eigenbase.util.mapping.MappingType#PARTIAL_SURJECTION} or stronger.
  */
 public PartialMapping(List<Integer> sourceList, int sourceCount, MappingType mappingType) {
   this.mappingType = mappingType;
   assert mappingType.isSingleSource();
   assert mappingType.isSingleTarget();
   int targetCount = sourceList.size();
   this.targets = new int[sourceCount];
   this.sources = new int[targetCount];
   Arrays.fill(sources, -1);
   for (int i = 0; i < sourceList.size(); ++i) {
     final int source = sourceList.get(i);
     sources[i] = source;
     if (source >= 0) {
       targets[source] = i;
     } else {
       assert !this.mappingType.isMandatorySource();
     }
   }
 }
예제 #23
0
  // implement SargExpr
  public SargIntervalSequence evaluateComplemented() {
    if (setOp == SargSetOperator.COMPLEMENT) {
      // Double negation is a nop
      return children.get(0).evaluate();
    }

    // Use DeMorgan's Law:  complement of union is intersection of
    // complements, and vice versa
    List<SargIntervalSequence> list = new ArrayList<SargIntervalSequence>();
    for (SargExpr child : children) {
      SargIntervalSequence newSeq = child.evaluateComplemented();
      list.add(newSeq);
    }
    switch (setOp) {
      case INTERSECTION:
        return evaluateUnion(list);
      case UNION:
        return evaluateIntersection(list);
      default:
        throw Util.newInternal(setOp.toString());
    }
  }
예제 #24
0
 /**
  * Trims a child relational expression, then adds back a dummy project to restore the fields that
  * were removed.
  *
  * <p>Sounds pointless? It causes unused fields to be removed further down the tree (towards the
  * leaves), but it ensure that the consuming relational expression continues to see the same
  * fields.
  *
  * @param rel Relational expression
  * @param input Input relational expression, whose fields to trim
  * @param fieldsUsed Bitmap of fields needed by the consumer
  * @return New relational expression and its field mapping
  */
 protected TrimResult trimChildRestore(
     RelNode rel, RelNode input, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
   TrimResult trimResult = trimChild(rel, input, fieldsUsed, extraFields);
   if (trimResult.right.isIdentity()) {
     return trimResult;
   }
   final RelDataType rowType = input.getRowType();
   List<RelDataTypeField> fieldList = rowType.getFieldList();
   final List<RexNode> exprList = new ArrayList<RexNode>();
   final List<String> nameList = rowType.getFieldNames();
   RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
   assert trimResult.right.getSourceCount() == fieldList.size();
   for (int i = 0; i < fieldList.size(); i++) {
     int source = trimResult.right.getTargetOpt(i);
     RelDataTypeField field = fieldList.get(i);
     exprList.add(
         source < 0
             ? rexBuilder.makeZeroLiteral(field.getType())
             : rexBuilder.makeInputRef(field.getType(), source));
   }
   RelNode project = CalcRel.createProject(trimResult.left, exprList, nameList);
   return new TrimResult(project, Mappings.createIdentity(fieldList.size()));
 }
예제 #25
0
  protected void explain_(RelNode rel, List<Pair<String, Object>> values) {
    final Map<String, Object> map = jsonBuilder.map();

    map.put("id", null); // ensure that id is the first attribute
    map.put("relOp", relJson.classToTypeName(rel.getClass()));
    for (Pair<String, Object> value : values) {
      if (value.right instanceof RelNode) {
        continue;
      }
      put(map, value.left, value.right);
    }
    // omit 'inputs: ["3"]' if "3" is the preceding rel
    final List<Object> list = explainInputs(rel.getInputs());
    if (list.size() != 1 || !list.get(0).equals(previousId)) {
      map.put("inputs", list);
    }

    final String id = Integer.toString(relIdMap.size());
    relIdMap.put(rel, id);
    map.put("id", id);

    relList.add(map);
    previousId = id;
  }
예제 #26
0
  /**
   * Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link org.eigenbase.rel.ValuesRel}.
   */
  public TrimResult trimFields(
      ValuesRel values, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = values.getRowType();
    final int fieldCount = rowType.getFieldCount();

    // If they are asking for no fields, we can't give them what they want,
    // because zero-column records are illegal. Give them the last field,
    // which is unlikely to be a system field.
    if (fieldsUsed.isEmpty()) {
      fieldsUsed = Util.bitSetBetween(fieldCount - 1, fieldCount);
    }

    // If all fields are used, return unchanged.
    if (fieldsUsed.equals(Util.bitSetBetween(0, fieldCount))) {
      Mapping mapping = Mappings.createIdentity(fieldCount);
      return new TrimResult(values, mapping);
    }

    List<List<RexLiteral>> newTuples = new ArrayList<List<RexLiteral>>();
    for (List<RexLiteral> tuple : values.getTuples()) {
      List<RexLiteral> newTuple = new ArrayList<RexLiteral>();
      for (int field : Util.toIter(fieldsUsed)) {
        newTuple.add(tuple.get(field));
      }
      newTuples.add(newTuple);
    }

    final Mapping mapping = createMapping(fieldsUsed, fieldCount);
    RelDataType newRowType =
        values
            .getCluster()
            .getTypeFactory()
            .createStructType(Mappings.apply3(mapping, rowType.getFieldList()));
    final ValuesRel newValues = new ValuesRel(values.getCluster(), newRowType, newTuples);
    return new TrimResult(newValues, mapping);
  }
  public int reduceExpr(int opOrdinal, List<Object> list) {
    final SqlParserUtil.ToTreeListItem betweenNode =
        (SqlParserUtil.ToTreeListItem) list.get(opOrdinal);
    SqlOperator op = betweenNode.getOperator();
    assert op == this;

    // Break the expression up into expressions. For example, a simple
    // expression breaks down as follows:
    //
    //            opOrdinal   endExp1
    //            |           |
    //     a + b BETWEEN c + d AND e + f
    //    |_____|       |_____|   |_____|
    //     exp0          exp1      exp2
    // Create the expression between 'BETWEEN' and 'AND'.
    final SqlParserPos pos = ((SqlNode) list.get(opOrdinal + 1)).getParserPosition();
    SqlNode exp1 = SqlParserUtil.toTreeEx(list, opOrdinal + 1, 0, SqlKind.AND);
    if ((opOrdinal + 2) >= list.size()) {
      SqlParserPos lastPos = ((SqlNode) list.get(list.size() - 1)).getParserPosition();
      final int line = lastPos.getEndLineNum();
      final int col = lastPos.getEndColumnNum() + 1;
      SqlParserPos errPos = new SqlParserPos(line, col, line, col);
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }
    final Object o = list.get(opOrdinal + 2);
    if (!(o instanceof SqlParserUtil.ToTreeListItem)) {
      SqlParserPos errPos = ((SqlNode) o).getParserPosition();
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }
    if (((SqlParserUtil.ToTreeListItem) o).getOperator().getKind() != SqlKind.AND) {
      SqlParserPos errPos = ((SqlParserUtil.ToTreeListItem) o).getPos();
      throw SqlUtil.newContextException(
          errPos, EigenbaseResource.instance().BetweenWithoutAnd.ex());
    }

    // Create the expression after 'AND', but stopping if we encounter an
    // operator of lower precedence.
    //
    // For example,
    //   a BETWEEN b AND c + d OR e
    // becomes
    //   (a BETWEEN b AND c + d) OR e
    // because OR has lower precedence than BETWEEN.
    SqlNode exp2 = SqlParserUtil.toTreeEx(list, opOrdinal + 3, getRightPrec(), SqlKind.OTHER);

    // Create the call.
    SqlNode exp0 = (SqlNode) list.get(opOrdinal - 1);
    SqlCall newExp =
        createCall(
            betweenNode.getPos(),
            exp0,
            exp1,
            exp2,
            SqlLiteral.createSymbol(flag, SqlParserPos.ZERO));

    // Replace all of the matched nodes with the single reduced node.
    SqlParserUtil.replaceSublist(list, opOrdinal - 1, opOrdinal + 4, newExp);

    // Return the ordinal of the new current node.
    return opOrdinal - 1;
  }
예제 #28
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);
  }
예제 #29
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link ProjectRel}. */
  public TrimResult trimFields(
      ProjectRel project, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = project.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RelNode input = project.getChild();
    final RelDataType inputRowType = input.getRowType();

    // Which fields are required from the input?
    BitSet inputFieldsUsed = new BitSet(inputRowType.getFieldCount());
    final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(inputFieldsUsed, inputExtraFields);
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        ord.e.accept(inputFinder);
      }
    }

    // Create input with trimmed columns.
    TrimResult trimResult = trimChild(project, 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(project, Mappings.createIdentity(fieldCount));
    }

    // Some parts of the system can't handle rows with zero fields, so
    // pretend that one field is used.
    if (fieldsUsed.cardinality() == 0) {
      final Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, 1);
      final RexLiteral expr =
          project.getCluster().getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
      RelDataType newRowType =
          project
              .getCluster()
              .getTypeFactory()
              .createStructType(
                  Collections.singletonList(expr.getType()), Collections.singletonList("DUMMY"));
      ProjectRel newProject =
          new ProjectRel(
              project.getCluster(),
              project.getCluster().traitSetOf(RelCollationImpl.EMPTY),
              newInput,
              Collections.<RexNode>singletonList(expr),
              newRowType,
              project.getFlags());
      return new TrimResult(newProject, mapping);
    }

    // Build new project expressions, and populate the mapping.
    List<RexNode> newProjectExprList = new ArrayList<RexNode>();
    final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput);
    final Mapping mapping =
        Mappings.create(MappingType.InverseSurjection, fieldCount, fieldsUsed.cardinality());
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        mapping.set(ord.i, newProjectExprList.size());
        RexNode newProjectExpr = ord.e.accept(shuttle);
        newProjectExprList.add(newProjectExpr);
      }
    }

    final RelDataType newRowType =
        project
            .getCluster()
            .getTypeFactory()
            .createStructType(Mappings.apply3(mapping, rowType.getFieldList()));

    final List<RelCollation> newCollations =
        RexUtil.apply(inputMapping, project.getCollationList());

    final RelNode newProject;
    if (RemoveTrivialProjectRule.isIdentity(
        newProjectExprList, newRowType, newInput.getRowType())) {
      // The new project would be the identity. It is equivalent to return
      // its child.
      newProject = newInput;
    } else {
      newProject =
          new ProjectRel(
              project.getCluster(),
              project
                  .getCluster()
                  .traitSetOf(
                      newCollations.isEmpty() ? RelCollationImpl.EMPTY : newCollations.get(0)),
              newInput,
              newProjectExprList,
              newRowType,
              project.getFlags());
      assert newProject.getClass() == project.getClass();
    }
    return new TrimResult(newProject, mapping);
  }