use of org.apache.calcite.rel.type.RelDataTypeFactory in project calcite by apache.
the class RelOptUtil method permute.
/**
* Creates a relational expression which permutes the output fields of a
* relational expression according to a permutation.
*
* <p>Optimizations:</p>
*
* <ul>
* <li>If the relational expression is a
* {@link org.apache.calcite.rel.logical.LogicalCalc} or
* {@link org.apache.calcite.rel.logical.LogicalProject} that is already
* acting as a permutation, combines the new permutation with the old;</li>
*
* <li>If the permutation is the identity, returns the original relational
* expression.</li>
* </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 LogicalCalc) {
LogicalCalc calc = (LogicalCalc) rel;
Permutation permutation1 = calc.getProgram().getPermutation();
if (permutation1 != null) {
Permutation permutation2 = permutation.product(permutation1);
return permute(rel, permutation2, null);
}
}
if (rel instanceof LogicalProject) {
Permutation permutation1 = ((LogicalProject) rel).getPermutation();
if (permutation1 != null) {
Permutation permutation2 = permutation.product(permutation1);
return permute(rel, permutation2, null);
}
}
final List<RelDataType> outputTypeList = new ArrayList<>();
final List<String> outputNameList = new ArrayList<>();
final List<RexNode> exprList = new ArrayList<>();
final List<RexLocalRef> projectRefList = new ArrayList<>();
final List<RelDataTypeField> fields = rel.getRowType().getFieldList();
final RelOptCluster cluster = rel.getCluster();
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(cluster.getRexBuilder().makeInputRef(fields.get(i).getType(), i));
final int source = permutation.getSource(i);
projectRefList.add(new RexLocalRef(source, fields.get(source).getType()));
}
final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
final RexProgram program = new RexProgram(rel.getRowType(), exprList, projectRefList, null, typeFactory.createStructType(outputTypeList, outputNameList));
return LogicalCalc.create(rel, program);
}
use of org.apache.calcite.rel.type.RelDataTypeFactory in project calcite by apache.
the class RelOptUtil method splitJoinCondition.
private static void splitJoinCondition(List<RelDataTypeField> sysFieldList, List<RelNode> inputs, RexNode condition, List<List<RexNode>> joinKeys, List<Integer> filterNulls, List<SqlOperator> rangeOp, List<RexNode> nonEquiList) {
final int sysFieldCount = sysFieldList.size();
final RelOptCluster cluster = inputs.get(0).getCluster();
final RexBuilder rexBuilder = cluster.getRexBuilder();
final RelDataTypeFactory typeFactory = cluster.getTypeFactory();
final ImmutableBitSet[] inputsRange = new ImmutableBitSet[inputs.size()];
int totalFieldCount = 0;
for (int i = 0; i < inputs.size(); i++) {
final int firstField = totalFieldCount + sysFieldCount;
totalFieldCount = firstField + inputs.get(i).getRowType().getFieldCount();
inputsRange[i] = ImmutableBitSet.range(firstField, totalFieldCount);
}
// adjustment array
int[] adjustments = new int[totalFieldCount];
for (int i = 0; i < inputs.size(); i++) {
final int adjustment = inputsRange[i].nextSetBit(0);
for (int j = adjustment; j < inputsRange[i].length(); j++) {
adjustments[j] = -adjustment;
}
}
if (condition instanceof RexCall) {
RexCall call = (RexCall) condition;
if (call.getKind() == SqlKind.AND) {
for (RexNode operand : call.getOperands()) {
splitJoinCondition(sysFieldList, inputs, operand, joinKeys, filterNulls, rangeOp, nonEquiList);
}
return;
}
RexNode leftKey = null;
RexNode rightKey = null;
int leftInput = 0;
int rightInput = 0;
List<RelDataTypeField> leftFields = null;
List<RelDataTypeField> rightFields = null;
boolean reverse = false;
call = collapseExpandedIsNotDistinctFromExpr(call, rexBuilder);
SqlKind kind = call.getKind();
// Only consider range operators if we haven't already seen one
if ((kind == SqlKind.EQUALS) || (filterNulls != null && kind == SqlKind.IS_NOT_DISTINCT_FROM) || (rangeOp != null && rangeOp.isEmpty() && (kind == SqlKind.GREATER_THAN || kind == SqlKind.GREATER_THAN_OR_EQUAL || kind == SqlKind.LESS_THAN || kind == SqlKind.LESS_THAN_OR_EQUAL))) {
final List<RexNode> operands = call.getOperands();
RexNode op0 = operands.get(0);
RexNode op1 = operands.get(1);
final ImmutableBitSet projRefs0 = InputFinder.bits(op0);
final ImmutableBitSet projRefs1 = InputFinder.bits(op1);
boolean foundBothInputs = false;
for (int i = 0; i < inputs.size() && !foundBothInputs; i++) {
if (projRefs0.intersects(inputsRange[i]) && projRefs0.union(inputsRange[i]).equals(inputsRange[i])) {
if (leftKey == null) {
leftKey = op0;
leftInput = i;
leftFields = inputs.get(leftInput).getRowType().getFieldList();
} else {
rightKey = op0;
rightInput = i;
rightFields = inputs.get(rightInput).getRowType().getFieldList();
reverse = true;
foundBothInputs = true;
}
} else if (projRefs1.intersects(inputsRange[i]) && projRefs1.union(inputsRange[i]).equals(inputsRange[i])) {
if (leftKey == null) {
leftKey = op1;
leftInput = i;
leftFields = inputs.get(leftInput).getRowType().getFieldList();
} else {
rightKey = op1;
rightInput = i;
rightFields = inputs.get(rightInput).getRowType().getFieldList();
foundBothInputs = true;
}
}
}
if ((leftKey != null) && (rightKey != null)) {
// replace right Key input ref
rightKey = rightKey.accept(new RelOptUtil.RexInputConverter(rexBuilder, rightFields, rightFields, adjustments));
// left key only needs to be adjusted if there are system
// fields, but do it for uniformity
leftKey = leftKey.accept(new RelOptUtil.RexInputConverter(rexBuilder, leftFields, leftFields, adjustments));
RelDataType leftKeyType = leftKey.getType();
RelDataType rightKeyType = rightKey.getType();
if (leftKeyType != rightKeyType) {
// perform casting
RelDataType targetKeyType = typeFactory.leastRestrictive(ImmutableList.of(leftKeyType, rightKeyType));
if (targetKeyType == null) {
throw new AssertionError("Cannot find common type for join keys " + leftKey + " (type " + leftKeyType + ") and " + rightKey + " (type " + rightKeyType + ")");
}
if (leftKeyType != targetKeyType) {
leftKey = rexBuilder.makeCast(targetKeyType, leftKey);
}
if (rightKeyType != targetKeyType) {
rightKey = rexBuilder.makeCast(targetKeyType, rightKey);
}
}
}
}
if ((rangeOp == null) && ((leftKey == null) || (rightKey == null))) {
// no equality join keys found yet:
// try transforming the condition to
// equality "join" conditions, e.g.
// f(LHS) > 0 ===> ( f(LHS) > 0 ) = TRUE,
// and make the RHS produce TRUE, but only if we're strictly
// looking for equi-joins
final ImmutableBitSet projRefs = InputFinder.bits(condition);
leftKey = null;
rightKey = null;
boolean foundInput = false;
for (int i = 0; i < inputs.size() && !foundInput; i++) {
if (inputsRange[i].contains(projRefs)) {
leftInput = i;
leftFields = inputs.get(leftInput).getRowType().getFieldList();
leftKey = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, leftFields, leftFields, adjustments));
rightKey = rexBuilder.makeLiteral(true);
// effectively performing an equality comparison
kind = SqlKind.EQUALS;
foundInput = true;
}
}
}
if ((leftKey != null) && (rightKey != null)) {
// found suitable join keys
// add them to key list, ensuring that if there is a
// non-equi join predicate, it appears at the end of the
// key list; also mark the null filtering property
addJoinKey(joinKeys.get(leftInput), leftKey, (rangeOp != null) && !rangeOp.isEmpty());
addJoinKey(joinKeys.get(rightInput), rightKey, (rangeOp != null) && !rangeOp.isEmpty());
if (filterNulls != null && kind == SqlKind.EQUALS) {
// nulls are considered not matching for equality comparison
// add the position of the most recently inserted key
filterNulls.add(joinKeys.get(leftInput).size() - 1);
}
if (rangeOp != null && kind != SqlKind.EQUALS && kind != SqlKind.IS_DISTINCT_FROM) {
if (reverse) {
kind = kind.reverse();
}
rangeOp.add(op(kind, call.getOperator()));
}
return;
}
// else fall through and add this condition as nonEqui condition
}
// The operator is not of RexCall type
// So we fail. Fall through.
// Add this condition to the list of non-equi-join conditions.
nonEquiList.add(condition);
}
use of org.apache.calcite.rel.type.RelDataTypeFactory in project calcite by apache.
the class SqlTypeUtil method makeNullableIfOperandsAre.
/**
* Recreates a given RelDataType with nullability iff any of the operands
* of a call are nullable.
*/
public static RelDataType makeNullableIfOperandsAre(final SqlValidator validator, final SqlValidatorScope scope, final SqlCall call, RelDataType type) {
for (SqlNode operand : call.getOperandList()) {
RelDataType operandType = validator.deriveType(scope, operand);
if (containsNullable(operandType)) {
RelDataTypeFactory typeFactory = validator.getTypeFactory();
type = typeFactory.createTypeWithNullability(type, true);
break;
}
}
return type;
}
use of org.apache.calcite.rel.type.RelDataTypeFactory in project calcite by apache.
the class AbstractNamespace method convertToStruct.
protected RelDataType convertToStruct(RelDataType type) {
// "MULTISET [<expr>, ...]" needs to be wrapped in a record if
// <expr> has a scalar type.
// For example, "MULTISET [8, 9]" has type
// "RECORD(INTEGER EXPR$0 NOT NULL) NOT NULL MULTISET NOT NULL".
final RelDataType componentType = type.getComponentType();
if (componentType == null || componentType.isStruct()) {
return type;
}
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
final RelDataType structType = toStruct(componentType, getNode());
final RelDataType collectionType;
switch(type.getSqlTypeName()) {
case ARRAY:
collectionType = typeFactory.createArrayType(structType, -1);
break;
case MULTISET:
collectionType = typeFactory.createMultisetType(structType, -1);
break;
default:
throw new AssertionError(type);
}
return typeFactory.createTypeWithNullability(collectionType, type.isNullable());
}
use of org.apache.calcite.rel.type.RelDataTypeFactory in project calcite by apache.
the class JoinNamespace method validateImpl.
// ~ Methods ----------------------------------------------------------------
protected RelDataType validateImpl(RelDataType targetRowType) {
RelDataType leftType = validator.getNamespace(join.getLeft()).getRowType();
RelDataType rightType = validator.getNamespace(join.getRight()).getRowType();
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
switch(join.getJoinType()) {
case LEFT:
rightType = typeFactory.createTypeWithNullability(rightType, true);
break;
case RIGHT:
leftType = typeFactory.createTypeWithNullability(leftType, true);
break;
case FULL:
leftType = typeFactory.createTypeWithNullability(leftType, true);
rightType = typeFactory.createTypeWithNullability(rightType, true);
break;
}
return typeFactory.createJoinType(leftType, rightType);
}
Aggregations