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);
      }
    }
 private void reduceNotNullableFilter(
     RelOptRuleCall call, FilterRel filter, RexCall rexCall, boolean reverse) {
   // If the expression is a IS [NOT] NULL on a non-nullable
   // column, then we can either remove the filter or replace
   // it with an EmptyRel.
   SqlOperator op = rexCall.getOperator();
   boolean alwaysTrue;
   if (op == SqlStdOperatorTable.isNullOperator
       || op == SqlStdOperatorTable.isUnknownOperator) {
     alwaysTrue = false;
   } else if (op == SqlStdOperatorTable.isNotNullOperator) {
     alwaysTrue = true;
   } else {
     return;
   }
   if (reverse) {
     alwaysTrue = !alwaysTrue;
   }
   RexNode operand = rexCall.getOperands()[0];
   if (operand instanceof RexInputRef) {
     RexInputRef inputRef = (RexInputRef) operand;
     if (!inputRef.getType().isNullable()) {
       if (alwaysTrue) {
         call.transformTo(filter.getChild());
       } else {
         call.transformTo(new EmptyRel(filter.getCluster(), filter.getRowType()));
       }
     }
   }
 }
Beispiel #3
0
 /**
  * Replaces the operands of a call. The new operands' types must match the old operands' types.
  */
 public static RexCall replaceOperands(RexCall call, RexNode[] operands) {
   if (call.operands == operands) {
     return call;
   }
   for (int i = 0; i < operands.length; i++) {
     RelDataType oldType = call.operands[i].getType();
     RelDataType newType = operands[i].getType();
     if (!oldType.isNullable() && newType.isNullable()) {
       throw Util.newInternal("invalid nullability");
     }
     assert (oldType.toString().equals(newType.toString()));
   }
   return new RexCall(call.getType(), call.getOperator(), operands);
 }
  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);
  }
Beispiel #5
0
 /**
  * Returns whether a list of expressions contains complex expressions, that is, a call whose
  * arguments are not {@link RexVariable} (or a subtype such as {@link RexInputRef}) or {@link
  * RexLiteral}.
  */
 public static boolean containComplexExprs(List<RexNode> exprs) {
   for (RexNode expr : exprs) {
     if (expr instanceof RexCall) {
       RexCall rexCall = (RexCall) expr;
       final RexNode[] operands = rexCall.getOperands();
       for (int j = 0; j < operands.length; j++) {
         RexNode operand = operands[j];
         if (!isAtomic(operand)) {
           return true;
         }
       }
     }
   }
   return false;
 }
Beispiel #6
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);
 }
Beispiel #7
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;
 }
    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);
    }
 // 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;
 }
Beispiel #10
0
 /**
  * Returns whether an array of exp contains aggregate function calls whose arguments are not
  * {@link RexInputRef}.s
  *
  * @param exprs Expressions
  * @param fail Whether to assert if there is such a function call
  */
 static boolean containNonTrivialAggs(RexNode[] exprs, boolean fail) {
   for (int i = 0; i < exprs.length; i++) {
     RexNode expr = exprs[i];
     if (expr instanceof RexCall) {
       RexCall rexCall = (RexCall) expr;
       if (rexCall.getOperator() instanceof SqlAggFunction) {
         final RexNode[] operands = rexCall.getOperands();
         for (int j = 0; j < operands.length; j++) {
           RexNode operand = operands[j];
           if (!(operand instanceof RexLocalRef)) {
             assert !fail : "contains non trivial agg";
             return true;
           }
         }
       }
     }
   }
   return false;
 }
Beispiel #11
0
  /**
   * Determines whether a {@link RexCall} requires decimal expansion. It usually requires expansion
   * if it has decimal operands.
   *
   * <p>Exceptions to this rule are:
   *
   * <ul>
   *   <li>isNull doesn't require expansion
   *   <li>It's okay to cast decimals to and from char types
   *   <li>It's okay to cast nulls as decimals
   *   <li>Casts require expansion if their return type is decimal
   *   <li>Reinterpret casts can handle a decimal operand
   * </ul>
   *
   * @param expr expression possibly in need of expansion
   * @param recurse whether to check nested calls
   * @return whether the expression requires expansion
   */
  public static boolean requiresDecimalExpansion(RexNode expr, boolean recurse) {
    if (!(expr instanceof RexCall)) {
      return false;
    }
    RexCall call = (RexCall) expr;

    boolean localCheck = true;
    switch (call.getKind()) {
      case Reinterpret:
      case IsNull:
        localCheck = false;
        break;
      case Cast:
        RelDataType lhsType = call.getType();
        RelDataType rhsType = call.operands[0].getType();
        if (rhsType.getSqlTypeName() == SqlTypeName.NULL) {
          return false;
        }
        if (SqlTypeUtil.inCharFamily(lhsType) || SqlTypeUtil.inCharFamily(rhsType)) {
          localCheck = false;
        } else if (SqlTypeUtil.isDecimal(lhsType) && (lhsType != rhsType)) {
          return true;
        }
        break;
      default:
        localCheck = call.getOperator().requiresDecimalExpansion();
    }

    if (localCheck) {
      if (SqlTypeUtil.isDecimal(call.getType())) {
        // NOTE jvs 27-Mar-2007: Depending on the type factory, the
        // result of a division may be decimal, even though both inputs
        // are integer.
        return true;
      }
      for (int i = 0; i < call.operands.length; i++) {
        if (SqlTypeUtil.isDecimal(call.operands[i].getType())) {
          return true;
        }
      }
    }
    return (recurse && requiresDecimalExpansion(call.operands, recurse));
  }
  /**
   * 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);
        }
    private void reduceCasts(RexCall outerCast) {
      RexNode[] operands = outerCast.getOperands();
      if (operands.length != 1) {
        return;
      }
      RelDataType outerCastType = outerCast.getType();
      RelDataType operandType = operands[0].getType();
      if (operandType.equals(outerCastType)) {
        removableCasts.add(outerCast);
        return;
      }

      // See if the reduction
      // CAST((CAST x AS type) AS type NOT NULL)
      // -> CAST(x AS type NOT NULL)
      // applies.  TODO jvs 15-Dec-2008:  consider
      // similar cases for precision changes.
      if (!(operands[0] instanceof RexCall)) {
        return;
      }
      RexCall innerCast = (RexCall) operands[0];
      if (innerCast.getOperator() != SqlStdOperatorTable.castFunc) {
        return;
      }
      if (innerCast.getOperands().length != 1) {
        return;
      }
      RelDataTypeFactory typeFactory = preparingStmt.getFarragoTypeFactory();
      RelDataType outerTypeNullable = typeFactory.createTypeWithNullability(outerCastType, true);
      RelDataType innerTypeNullable = typeFactory.createTypeWithNullability(operandType, true);
      if (outerTypeNullable != innerTypeNullable) {
        return;
      }
      if (operandType.isNullable()) {
        removableCasts.add(innerCast);
      }
    }
Beispiel #15
0
 /** Converts an expression from {@link RexNode} to {@link SqlNode} format. */
 SqlNode toSql(RexProgram program, RexNode rex) {
   if (rex instanceof RexLocalRef) {
     final int index = ((RexLocalRef) rex).getIndex();
     return toSql(program, program.getExprList().get(index));
   } else if (rex instanceof RexInputRef) {
     return field(((RexInputRef) rex).getIndex());
   } else if (rex instanceof RexLiteral) {
     final RexLiteral literal = (RexLiteral) rex;
     switch (literal.getTypeName().getFamily()) {
       case CHARACTER:
         return SqlLiteral.createCharString((String) literal.getValue2(), POS);
       case NUMERIC:
       case EXACT_NUMERIC:
         return SqlLiteral.createExactNumeric(literal.getValue().toString(), POS);
       case APPROXIMATE_NUMERIC:
         return SqlLiteral.createApproxNumeric(literal.getValue().toString(), POS);
       case BOOLEAN:
         return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS);
       case DATE:
         return SqlLiteral.createDate((Calendar) literal.getValue(), POS);
       case TIME:
         return SqlLiteral.createTime(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case TIMESTAMP:
         return SqlLiteral.createTimestamp(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case ANY:
         switch (literal.getTypeName()) {
           case NULL:
             return SqlLiteral.createNull(POS);
             // fall through
         }
       default:
         throw new AssertionError(literal + ": " + literal.getTypeName());
     }
   } else if (rex instanceof RexCall) {
     final RexCall call = (RexCall) rex;
     final SqlOperator op = call.getOperator();
     final List<SqlNode> nodeList = toSql(program, call.getOperands());
     if (op == SqlStdOperatorTable.CAST) {
       RelDataType type = call.getType();
       if (type.getSqlTypeName() == SqlTypeName.VARCHAR
           && dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) {
         // MySQL doesn't have a VARCHAR type, only CHAR.
         nodeList.add(
             new SqlDataTypeSpec(
                 new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS));
       } else {
         nodeList.add(toSql(type));
       }
     }
     if (op == SqlStdOperatorTable.CASE) {
       final SqlNode valueNode;
       final List<SqlNode> whenList = Expressions.list();
       final List<SqlNode> thenList = Expressions.list();
       final SqlNode elseNode;
       if (nodeList.size() % 2 == 0) {
         // switched:
         //   "case x when v1 then t1 when v2 then t2 ... else e end"
         valueNode = nodeList.get(0);
         for (int i = 1; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       } else {
         // other: "case when w1 then t1 when w2 then t2 ... else e end"
         valueNode = null;
         for (int i = 0; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       }
       elseNode = nodeList.get(nodeList.size() - 1);
       return op.createCall(
           POS,
           valueNode,
           new SqlNodeList(whenList, POS),
           new SqlNodeList(thenList, POS),
           elseNode);
     }
     if (op instanceof SqlBinaryOperator && nodeList.size() > 2) {
       // In RexNode trees, OR and AND have any number of children;
       // SqlCall requires exactly 2. So, convert to a left-deep binary tree.
       return createLeftCall(op, nodeList);
     }
     return op.createCall(new SqlNodeList(nodeList, POS));
   } else {
     throw new AssertionError(rex);
   }
 }
  /**
   * Reduces a list of expressions.
   *
   * @param rel Relational expression
   * @param expList List of expressions, modified in place
   * @return whether reduction found something to change, and succeeded
   */
  static boolean reduceExpressions(RelNode rel, List<RexNode> expList) {
    RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

    // Find reducible expressions.
    FarragoSessionPlanner planner = (FarragoSessionPlanner) rel.getCluster().getPlanner();
    FarragoSessionPreparingStmt preparingStmt = planner.getPreparingStmt();
    List<RexNode> constExps = new ArrayList<RexNode>();
    List<Boolean> addCasts = new ArrayList<Boolean>();
    List<RexNode> removableCasts = new ArrayList<RexNode>();
    findReducibleExps(preparingStmt, expList, constExps, addCasts, removableCasts);
    if (constExps.isEmpty() && removableCasts.isEmpty()) {
      return false;
    }

    // Remove redundant casts before reducing constant expressions.
    // If the argument to the redundant cast is a reducible constant,
    // reducing that argument to a constant first will result in not being
    // able to locate the original cast expression.
    if (!removableCasts.isEmpty()) {
      List<RexNode> reducedExprs = new ArrayList<RexNode>();
      List<Boolean> noCasts = new ArrayList<Boolean>();
      for (RexNode exp : removableCasts) {
        RexCall call = (RexCall) exp;
        reducedExprs.add(call.getOperands()[0]);
        noCasts.add(false);
      }
      RexReplacer replacer = new RexReplacer(rexBuilder, removableCasts, reducedExprs, noCasts);
      replacer.apply(expList);
    }

    if (constExps.isEmpty()) {
      return true;
    }

    // Compute the values they reduce to.
    List<RexNode> reducedValues = new ArrayList<RexNode>();
    ReentrantValuesStmt reentrantStmt =
        new ReentrantValuesStmt(
            preparingStmt.getRootStmtContext(), rexBuilder, constExps, reducedValues);
    FarragoSession session = getSession(rel);
    reentrantStmt.execute(session, true);
    if (reentrantStmt.failed) {
      return false;
    }

    // For ProjectRel, we have to be sure to preserve the result
    // types, so always cast regardless of the expression type.
    // For other RelNodes like FilterRel, in general, this isn't necessary,
    // and the presence of casts could hinder other rules such as sarg
    // analysis, which require bare literals.  But there are special cases,
    // like when the expression is a UDR argument, that need to be
    // handled as special cases.
    if (rel instanceof ProjectRel) {
      for (int i = 0; i < reducedValues.size(); i++) {
        addCasts.set(i, true);
      }
    }

    RexReplacer replacer = new RexReplacer(rexBuilder, constExps, reducedValues, addCasts);
    replacer.apply(expList);
    return true;
  }
Beispiel #17
0
 public static boolean canReinterpretOverflow(RexCall call) {
   assert (call.isA(RexKind.Reinterpret)) : "call is not a reinterpret";
   return call.operands.length > 1;
 }