use of org.apache.calcite.rel.metadata.RelColumnMapping in project calcite by apache.
the class TableFunctionReturnTypeInference method addOutputColumn.
private void addOutputColumn(List<String> expandedFieldNames, List<RelDataType> expandedOutputTypes, int iInputColumn, int iCursor, SqlOperatorBinding opBinding, RelDataTypeField cursorField) {
columnMappings.add(new RelColumnMapping(expandedFieldNames.size(), iCursor, iInputColumn, !isPassthrough));
// As a special case, system fields are implicitly NOT NULL.
// A badly behaved UDX can still provide NULL values, so the
// system must ensure that each generated system field has a
// reasonable value.
boolean nullable = true;
if (opBinding instanceof SqlCallBinding) {
SqlCallBinding sqlCallBinding = (SqlCallBinding) opBinding;
if (sqlCallBinding.getValidator().isSystemField(cursorField)) {
nullable = false;
}
}
RelDataType nullableType = opBinding.getTypeFactory().createTypeWithNullability(cursorField.getType(), nullable);
// Make sure there are no duplicates in the output column names
for (String fieldName : expandedFieldNames) {
if (fieldName.equals(cursorField.getName())) {
throw opBinding.newError(RESOURCE.duplicateColumnName(cursorField.getName()));
}
}
expandedOutputTypes.add(nullableType);
expandedFieldNames.add(cursorField.getName());
}
use of org.apache.calcite.rel.metadata.RelColumnMapping in project calcite by apache.
the class FilterTableFunctionTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
LogicalFilter filter = call.rel(0);
LogicalTableFunctionScan funcRel = call.rel(1);
Set<RelColumnMapping> columnMappings = funcRel.getColumnMappings();
if (columnMappings == null || columnMappings.isEmpty()) {
// possible.
return;
}
List<RelNode> funcInputs = funcRel.getInputs();
if (funcInputs.size() != 1) {
// offsetting field indices, similar to join
return;
}
// TODO: support mappings other than 1-to-1
if (funcRel.getRowType().getFieldCount() != funcInputs.get(0).getRowType().getFieldCount()) {
return;
}
for (RelColumnMapping mapping : columnMappings) {
if (mapping.iInputColumn != mapping.iOutputColumn) {
return;
}
if (mapping.derived) {
return;
}
}
final List<RelNode> newFuncInputs = new ArrayList<RelNode>();
final RelOptCluster cluster = funcRel.getCluster();
final RexNode condition = filter.getCondition();
// create filters on top of each func input, modifying the filter
// condition to reference the child instead
RexBuilder rexBuilder = filter.getCluster().getRexBuilder();
List<RelDataTypeField> origFields = funcRel.getRowType().getFieldList();
// TODO: these need to be non-zero once we
// support arbitrary mappings
int[] adjustments = new int[origFields.size()];
for (RelNode funcInput : funcInputs) {
RexNode newCondition = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, origFields, funcInput.getRowType().getFieldList(), adjustments));
newFuncInputs.add(LogicalFilter.create(funcInput, newCondition));
}
// create a new UDX whose children are the filters created above
LogicalTableFunctionScan newFuncRel = LogicalTableFunctionScan.create(cluster, newFuncInputs, funcRel.getCall(), funcRel.getElementType(), funcRel.getRowType(), columnMappings);
call.transformTo(newFuncRel);
}
use of org.apache.calcite.rel.metadata.RelColumnMapping in project calcite by apache.
the class TableFunctionReturnTypeInference method inferReturnType.
public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
columnMappings = new HashSet<RelColumnMapping>();
RelDataType unexpandedOutputType = protoType.apply(opBinding.getTypeFactory());
List<RelDataType> expandedOutputTypes = new ArrayList<RelDataType>();
List<String> expandedFieldNames = new ArrayList<String>();
for (RelDataTypeField field : unexpandedOutputType.getFieldList()) {
RelDataType fieldType = field.getType();
String fieldName = field.getName();
if (fieldType.getSqlTypeName() != SqlTypeName.CURSOR) {
expandedOutputTypes.add(fieldType);
expandedFieldNames.add(fieldName);
continue;
}
// Look up position of cursor parameter with same name as output
// field, also counting how many cursors appear before it
// (need this for correspondence with RelNode child position).
int paramOrdinal = -1;
int iCursor = 0;
for (int i = 0; i < paramNames.size(); ++i) {
if (paramNames.get(i).equals(fieldName)) {
paramOrdinal = i;
break;
}
RelDataType cursorType = opBinding.getCursorOperand(i);
if (cursorType != null) {
++iCursor;
}
}
assert paramOrdinal != -1;
// Translate to actual argument type.
boolean isRowOp = false;
List<String> columnNames = new ArrayList<String>();
RelDataType cursorType = opBinding.getCursorOperand(paramOrdinal);
if (cursorType == null) {
isRowOp = true;
String parentCursorName = opBinding.getColumnListParamInfo(paramOrdinal, fieldName, columnNames);
assert parentCursorName != null;
paramOrdinal = -1;
iCursor = 0;
for (int i = 0; i < paramNames.size(); ++i) {
if (paramNames.get(i).equals(parentCursorName)) {
paramOrdinal = i;
break;
}
cursorType = opBinding.getCursorOperand(i);
if (cursorType != null) {
++iCursor;
}
}
cursorType = opBinding.getCursorOperand(paramOrdinal);
assert cursorType != null;
}
// And expand. Function output is always nullable... except system
// fields.
int iInputColumn;
if (isRowOp) {
for (String columnName : columnNames) {
iInputColumn = -1;
RelDataTypeField cursorField = null;
for (RelDataTypeField cField : cursorType.getFieldList()) {
++iInputColumn;
if (cField.getName().equals(columnName)) {
cursorField = cField;
break;
}
}
addOutputColumn(expandedFieldNames, expandedOutputTypes, iInputColumn, iCursor, opBinding, cursorField);
}
} else {
iInputColumn = -1;
for (RelDataTypeField cursorField : cursorType.getFieldList()) {
++iInputColumn;
addOutputColumn(expandedFieldNames, expandedOutputTypes, iInputColumn, iCursor, opBinding, cursorField);
}
}
}
return opBinding.getTypeFactory().createStructType(expandedOutputTypes, expandedFieldNames);
}
use of org.apache.calcite.rel.metadata.RelColumnMapping in project calcite by apache.
the class SqlToRelConverter method convertCollectionTable.
protected void convertCollectionTable(Blackboard bb, SqlCall call) {
final SqlOperator operator = call.getOperator();
if (operator == SqlStdOperatorTable.TABLESAMPLE) {
final String sampleName = SqlLiteral.unchain(call.operand(0)).getValueAs(String.class);
datasetStack.push(sampleName);
SqlCall cursorCall = call.operand(1);
SqlNode query = cursorCall.operand(0);
RelNode converted = convertQuery(query, false, false).rel;
bb.setRoot(converted, false);
datasetStack.pop();
return;
}
replaceSubQueries(bb, call, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
// Expand table macro if possible. It's more efficient than
// LogicalTableFunctionScan.
final SqlCallBinding callBinding = new SqlCallBinding(bb.scope.getValidator(), bb.scope, call);
if (operator instanceof SqlUserDefinedTableMacro) {
final SqlUserDefinedTableMacro udf = (SqlUserDefinedTableMacro) operator;
final TranslatableTable table = udf.getTable(typeFactory, callBinding.operands());
final RelDataType rowType = table.getRowType(typeFactory);
RelOptTable relOptTable = RelOptTableImpl.create(null, rowType, table, udf.getNameAsId().names);
RelNode converted = toRel(relOptTable);
bb.setRoot(converted, true);
return;
}
Type elementType;
if (operator instanceof SqlUserDefinedTableFunction) {
SqlUserDefinedTableFunction udtf = (SqlUserDefinedTableFunction) operator;
elementType = udtf.getElementType(typeFactory, callBinding.operands());
} else {
elementType = null;
}
RexNode rexCall = bb.convertExpression(call);
final List<RelNode> inputs = bb.retrieveCursors();
Set<RelColumnMapping> columnMappings = getColumnMappings(operator);
LogicalTableFunctionScan callRel = LogicalTableFunctionScan.create(cluster, inputs, rexCall, elementType, validator.getValidatedNodeType(call), columnMappings);
bb.setRoot(callRel, true);
afterTableFunction(bb, call, callRel);
}
Aggregations