/** * Generates a cast from one row type to another * * @param rexBuilder RexBuilder to use for constructing casts * @param lhsRowType target row type * @param rhsRowType source row type; fields must be 1-to-1 with lhsRowType, in same order * @return cast expressions */ public static RexNode[] generateCastExpressions( RexBuilder rexBuilder, RelDataType lhsRowType, RelDataType rhsRowType) { int n = rhsRowType.getFieldCount(); assert n == lhsRowType.getFieldCount() : "field count: lhs [" + lhsRowType + "] rhs [" + rhsRowType + "]"; RexNode[] rhsExps = new RexNode[n]; for (int i = 0; i < n; ++i) { rhsExps[i] = rexBuilder.makeInputRef(rhsRowType.getFields()[i].getType(), i); } return generateCastExpressions(rexBuilder, lhsRowType, rhsExps); }
/** * 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; }
/** * 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; }
/** * Generates a cast for a row type. * * @param rexBuilder RexBuilder to use for constructing casts * @param lhsRowType target row type * @param rhsExps expressions to be cast * @return cast expressions */ public static RexNode[] generateCastExpressions( RexBuilder rexBuilder, RelDataType lhsRowType, RexNode[] rhsExps) { RelDataTypeField[] lhsFields = lhsRowType.getFields(); final int fieldCount = lhsFields.length; RexNode[] castExps = new RexNode[fieldCount]; assert fieldCount == rhsExps.length; for (int i = 0; i < fieldCount; ++i) { RelDataTypeField lhsField = lhsFields[i]; RelDataType lhsType = lhsField.getType(); RelDataType rhsType = rhsExps[i].getType(); if (lhsType.equals(rhsType)) { castExps[i] = rhsExps[i]; } else { castExps[i] = rexBuilder.makeCast(lhsType, rhsExps[i]); } } return castExps; }
// 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; }
/** * Creates a new SargFactory. * * @param rexBuilder factory for instances of {@link RexNode}, needed internally in the sarg * representation, and also for recomposing sargs into equivalent rex trees */ public SargFactory(RexBuilder rexBuilder) { this.rexBuilder = rexBuilder; rexNull = rexBuilder.constantNull(); }