use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class DelegatingScope method resolveInNamespace.
/**
* If a record type allows implicit references to fields, recursively looks
* into the fields. Otherwise returns immediately.
*/
void resolveInNamespace(SqlValidatorNamespace ns, boolean nullable, List<String> names, SqlNameMatcher nameMatcher, Path path, Resolved resolved) {
if (names.isEmpty()) {
resolved.found(ns, nullable, this, path, null);
return;
}
final RelDataType rowType = ns.getRowType();
if (rowType.isStruct()) {
SqlValidatorTable validatorTable = ns.getTable();
if (validatorTable instanceof Prepare.PreparingTable) {
Table t = ((Prepare.PreparingTable) validatorTable).unwrap(Table.class);
if (t instanceof CustomColumnResolvingTable) {
final List<Pair<RelDataTypeField, List<String>>> entries = ((CustomColumnResolvingTable) t).resolveColumn(rowType, validator.getTypeFactory(), names);
for (Pair<RelDataTypeField, List<String>> entry : entries) {
final RelDataTypeField field = entry.getKey();
final List<String> remainder = entry.getValue();
final SqlValidatorNamespace ns2 = new FieldNamespace(validator, field.getType());
final Step path2 = path.plus(rowType, field.getIndex(), field.getName(), StructKind.FULLY_QUALIFIED);
resolveInNamespace(ns2, nullable, remainder, nameMatcher, path2, resolved);
}
return;
}
}
final String name = names.get(0);
final RelDataTypeField field0 = nameMatcher.field(rowType, name);
if (field0 != null) {
final SqlValidatorNamespace ns2 = ns.lookupChild(field0.getName());
final Step path2 = path.plus(rowType, field0.getIndex(), field0.getName(), StructKind.FULLY_QUALIFIED);
resolveInNamespace(ns2, nullable, names.subList(1, names.size()), nameMatcher, path2, resolved);
} else {
for (RelDataTypeField field : rowType.getFieldList()) {
switch(field.getType().getStructKind()) {
case PEEK_FIELDS:
case PEEK_FIELDS_DEFAULT:
case PEEK_FIELDS_NO_EXPAND:
final Step path2 = path.plus(rowType, field.getIndex(), field.getName(), field.getType().getStructKind());
final SqlValidatorNamespace ns2 = ns.lookupChild(field.getName());
resolveInNamespace(ns2, nullable, names, nameMatcher, path2, resolved);
}
}
}
}
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class SetopOperandTypeChecker method checkOperandTypes.
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
assert callBinding.getOperandCount() == 2 : "setops are binary (for now)";
final RelDataType[] argTypes = new RelDataType[callBinding.getOperandCount()];
int colCount = -1;
final SqlValidator validator = callBinding.getValidator();
for (int i = 0; i < argTypes.length; i++) {
final RelDataType argType = argTypes[i] = callBinding.getOperandType(i);
if (!argType.isStruct()) {
if (throwOnFailure) {
throw new AssertionError("setop arg must be a struct");
} else {
return false;
}
}
// Each operand must have the same number of columns.
final List<RelDataTypeField> fields = argType.getFieldList();
if (i == 0) {
colCount = fields.size();
continue;
}
if (fields.size() != colCount) {
if (throwOnFailure) {
SqlNode node = callBinding.operand(i);
if (node instanceof SqlSelect) {
node = ((SqlSelect) node).getSelectList();
}
throw validator.newValidationError(node, RESOURCE.columnCountMismatchInSetop(callBinding.getOperator().getName()));
} else {
return false;
}
}
}
// column j.
for (int i = 0; i < colCount; i++) {
final int i2 = i;
final RelDataType type = callBinding.getTypeFactory().leastRestrictive(new AbstractList<RelDataType>() {
public RelDataType get(int index) {
return argTypes[index].getFieldList().get(i2).getType();
}
public int size() {
return argTypes.length;
}
});
if (type == null) {
if (throwOnFailure) {
SqlNode field = SqlUtil.getSelectListItem(callBinding.operand(0), i);
throw validator.newValidationError(field, // 1-based
RESOURCE.columnTypeMismatchInSetop(// 1-based
i + 1, callBinding.getOperator().getName()));
} else {
return false;
}
}
}
return true;
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class ProjectWindowTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final LogicalProject project = call.rel(0);
final LogicalWindow window = call.rel(1);
final RelOptCluster cluster = window.getCluster();
final List<RelDataTypeField> rowTypeWindowInput = window.getInput().getRowType().getFieldList();
final int windowInputColumn = rowTypeWindowInput.size();
// Record the window input columns which are actually referred
// either in the LogicalProject above LogicalWindow or LogicalWindow itself
// (Note that the constants used in LogicalWindow are not considered here)
final ImmutableBitSet beReferred = findReference(project, window);
// it is impossible to trim anyone of them out
if (beReferred.cardinality() == windowInputColumn) {
return;
}
// Put a DrillProjectRel below LogicalWindow
final List<RexNode> exps = new ArrayList<>();
final RelDataTypeFactory.Builder builder = cluster.getTypeFactory().builder();
// Keep only the fields which are referred
for (int index : BitSets.toIter(beReferred)) {
final RelDataTypeField relDataTypeField = rowTypeWindowInput.get(index);
exps.add(new RexInputRef(index, relDataTypeField.getType()));
builder.add(relDataTypeField);
}
final LogicalProject projectBelowWindow = new LogicalProject(cluster, window.getTraitSet(), window.getInput(), exps, builder.build());
// Create a new LogicalWindow with necessary inputs only
final List<Window.Group> groups = new ArrayList<>();
// As the un-referred columns are trimmed by the LogicalProject,
// the indices specified in LogicalWindow would need to be adjusted
final RexShuttle indexAdjustment = new RexShuttle() {
@Override
public RexNode visitInputRef(RexInputRef inputRef) {
final int newIndex = getAdjustedIndex(inputRef.getIndex(), beReferred, windowInputColumn);
return new RexInputRef(newIndex, inputRef.getType());
}
@Override
public RexNode visitCall(final RexCall call) {
if (call instanceof Window.RexWinAggCall) {
boolean[] update = { false };
final List<RexNode> clonedOperands = visitList(call.operands, update);
if (update[0]) {
return new Window.RexWinAggCall((SqlAggFunction) call.getOperator(), call.getType(), clonedOperands, ((Window.RexWinAggCall) call).ordinal, ((Window.RexWinAggCall) call).distinct);
} else {
return call;
}
} else {
return super.visitCall(call);
}
}
};
int aggCallIndex = windowInputColumn;
final RelDataTypeFactory.Builder outputBuilder = cluster.getTypeFactory().builder();
outputBuilder.addAll(projectBelowWindow.getRowType().getFieldList());
for (Window.Group group : window.groups) {
final ImmutableBitSet.Builder keys = ImmutableBitSet.builder();
final List<RelFieldCollation> orderKeys = new ArrayList<>();
final List<Window.RexWinAggCall> aggCalls = new ArrayList<>();
// Adjust keys
for (int index : group.keys) {
keys.set(getAdjustedIndex(index, beReferred, windowInputColumn));
}
// Adjust orderKeys
for (RelFieldCollation relFieldCollation : group.orderKeys.getFieldCollations()) {
final int index = relFieldCollation.getFieldIndex();
orderKeys.add(relFieldCollation.copy(getAdjustedIndex(index, beReferred, windowInputColumn)));
}
// Adjust Window Functions
for (Window.RexWinAggCall rexWinAggCall : group.aggCalls) {
aggCalls.add((Window.RexWinAggCall) rexWinAggCall.accept(indexAdjustment));
final RelDataTypeField relDataTypeField = window.getRowType().getFieldList().get(aggCallIndex);
outputBuilder.add(relDataTypeField);
++aggCallIndex;
}
groups.add(new Window.Group(keys.build(), group.isRows, group.lowerBound, group.upperBound, RelCollations.of(orderKeys), aggCalls));
}
final LogicalWindow newLogicalWindow = LogicalWindow.create(window.getTraitSet(), projectBelowWindow, window.constants, outputBuilder.build(), groups);
// Modify the top LogicalProject
final List<RexNode> topProjExps = new ArrayList<>();
for (RexNode rexNode : project.getChildExps()) {
topProjExps.add(rexNode.accept(indexAdjustment));
}
final LogicalProject newTopProj = project.copy(newLogicalWindow.getTraitSet(), newLogicalWindow, topProjExps, project.getRowType());
if (ProjectRemoveRule.isTrivial(newTopProj)) {
call.transformTo(newLogicalWindow);
} else {
call.transformTo(newTopProj);
}
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class SemiJoinJoinTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
SemiJoin semiJoin = call.rel(0);
final Join join = call.rel(1);
if (join instanceof SemiJoin) {
return;
}
final ImmutableIntList leftKeys = semiJoin.getLeftKeys();
final ImmutableIntList rightKeys = semiJoin.getRightKeys();
// X is the left child of the join below the semi-join
// Y is the right child of the join below the semi-join
// Z is the right child of the semi-join
int nFieldsX = join.getLeft().getRowType().getFieldList().size();
int nFieldsY = join.getRight().getRowType().getFieldList().size();
int nFieldsZ = semiJoin.getRight().getRowType().getFieldList().size();
int nTotalFields = nFieldsX + nFieldsY + nFieldsZ;
List<RelDataTypeField> fields = new ArrayList<RelDataTypeField>();
// create a list of fields for the full join result; note that
// we can't simply use the fields from the semi-join because the
// row-type of a semi-join only includes the left hand side fields
List<RelDataTypeField> joinFields = semiJoin.getRowType().getFieldList();
for (int i = 0; i < (nFieldsX + nFieldsY); i++) {
fields.add(joinFields.get(i));
}
joinFields = semiJoin.getRight().getRowType().getFieldList();
for (int i = 0; i < nFieldsZ; i++) {
fields.add(joinFields.get(i));
}
// determine which operands below the semi-join are the actual
// Rels that participate in the semi-join
int nKeysFromX = 0;
for (int leftKey : leftKeys) {
if (leftKey < nFieldsX) {
nKeysFromX++;
}
}
// otherwise, a semi-join wouldn't have been created
assert (nKeysFromX == 0) || (nKeysFromX == leftKeys.size());
// need to convert the semi-join condition and possibly the keys
RexNode newSemiJoinFilter;
List<Integer> newLeftKeys;
int[] adjustments = new int[nTotalFields];
if (nKeysFromX > 0) {
// (X, Y, Z) --> (X, Z, Y)
// semiJoin(X, Z)
// pass 0 as Y's adjustment because there shouldn't be any
// references to Y in the semi-join filter
setJoinAdjustments(adjustments, nFieldsX, nFieldsY, nFieldsZ, 0, -nFieldsY);
newSemiJoinFilter = semiJoin.getCondition().accept(new RelOptUtil.RexInputConverter(semiJoin.getCluster().getRexBuilder(), fields, adjustments));
newLeftKeys = leftKeys;
} else {
// (X, Y, Z) --> (X, Y, Z)
// semiJoin(Y, Z)
setJoinAdjustments(adjustments, nFieldsX, nFieldsY, nFieldsZ, -nFieldsX, -nFieldsX);
newSemiJoinFilter = semiJoin.getCondition().accept(new RelOptUtil.RexInputConverter(semiJoin.getCluster().getRexBuilder(), fields, adjustments));
newLeftKeys = RelOptUtil.adjustKeys(leftKeys, -nFieldsX);
}
// create the new join
RelNode leftSemiJoinOp;
if (nKeysFromX > 0) {
leftSemiJoinOp = join.getLeft();
} else {
leftSemiJoinOp = join.getRight();
}
SemiJoin newSemiJoin = SemiJoin.create(leftSemiJoinOp, semiJoin.getRight(), newSemiJoinFilter, ImmutableIntList.copyOf(newLeftKeys), rightKeys);
RelNode leftJoinRel;
RelNode rightJoinRel;
if (nKeysFromX > 0) {
leftJoinRel = newSemiJoin;
rightJoinRel = join.getRight();
} else {
leftJoinRel = join.getLeft();
rightJoinRel = newSemiJoin;
}
RelNode newJoinRel = join.copy(join.getTraitSet(), join.getCondition(), leftJoinRel, rightJoinRel, join.getJoinType(), join.isSemiJoinDone());
call.transformTo(newJoinRel);
}
use of org.apache.calcite.rel.type.RelDataTypeField in project calcite by apache.
the class RexSubQuery method scalar.
/**
* Creates a scalar sub-query.
*/
public static RexSubQuery scalar(RelNode rel) {
final List<RelDataTypeField> fieldList = rel.getRowType().getFieldList();
assert fieldList.size() == 1;
final RelDataTypeFactory typeFactory = rel.getCluster().getTypeFactory();
final RelDataType type = typeFactory.createTypeWithNullability(fieldList.get(0).getType(), true);
return new RexSubQuery(type, SqlStdOperatorTable.SCALAR_QUERY, ImmutableList.<RexNode>of(), rel);
}
Aggregations