use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method getCorrelationUse.
private CorrelationUse getCorrelationUse(Blackboard bb, final RelNode r0) {
final Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(r0);
if (correlatedVariables.isEmpty()) {
return null;
}
final ImmutableBitSet.Builder requiredColumns = ImmutableBitSet.builder();
final List<CorrelationId> correlNames = Lists.newArrayList();
// All correlations must refer the same namespace since correlation
// produces exactly one correlation source.
// The same source might be referenced by different variables since
// DeferredLookups are not de-duplicated at create time.
SqlValidatorNamespace prevNs = null;
for (CorrelationId correlName : correlatedVariables) {
DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
RexFieldAccess fieldAccess = lookup.getFieldAccess(correlName);
String originalRelName = lookup.getOriginalRelName();
String originalFieldName = fieldAccess.getField().getName();
final SqlNameMatcher nameMatcher = lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl();
lookup.bb.scope.resolve(ImmutableList.of(originalRelName), nameMatcher, false, resolved);
assert resolved.count() == 1;
final SqlValidatorScope.Resolve resolve = resolved.only();
final SqlValidatorNamespace foundNs = resolve.namespace;
final RelDataType rowType = resolve.rowType();
final int childNamespaceIndex = resolve.path.steps().get(0).i;
final SqlValidatorScope ancestorScope = resolve.scope;
boolean correlInCurrentScope = ancestorScope == bb.scope;
if (!correlInCurrentScope) {
continue;
}
if (prevNs == null) {
prevNs = foundNs;
} else {
assert prevNs == foundNs : "All correlation variables should resolve" + " to the same namespace." + " Prev ns=" + prevNs + ", new ns=" + foundNs;
}
int namespaceOffset = 0;
if (childNamespaceIndex > 0) {
// of output types from all the preceding namespaces
assert ancestorScope instanceof ListScope;
List<SqlValidatorNamespace> children = ((ListScope) ancestorScope).getChildren();
for (int i = 0; i < childNamespaceIndex; i++) {
SqlValidatorNamespace child = children.get(i);
namespaceOffset += child.getRowType().getFieldCount();
}
}
RexFieldAccess topLevelFieldAccess = fieldAccess;
while (topLevelFieldAccess.getReferenceExpr() instanceof RexFieldAccess) {
topLevelFieldAccess = (RexFieldAccess) topLevelFieldAccess.getReferenceExpr();
}
final RelDataTypeField field = rowType.getFieldList().get(topLevelFieldAccess.getField().getIndex() - namespaceOffset);
int pos = namespaceOffset + field.getIndex();
assert field.getType() == topLevelFieldAccess.getField().getType();
assert pos != -1;
if (bb.mapRootRelToFieldProjection.containsKey(bb.root)) {
// bb.root is an aggregate and only projects group by
// keys.
Map<Integer, Integer> exprProjection = bb.mapRootRelToFieldProjection.get(bb.root);
// the root of the outer relation.
if (exprProjection.containsKey(pos)) {
pos = exprProjection.get(pos);
} else {
// correl not grouped
throw new AssertionError("Identifier '" + originalRelName + "." + originalFieldName + "' is not a group expr");
}
}
requiredColumns.set(pos);
correlNames.add(correlName);
}
if (correlNames.isEmpty()) {
// None of the correlating variables originated in this scope.
return null;
}
RelNode r = r0;
if (correlNames.size() > 1) {
// The same table was referenced more than once.
// So we deduplicate.
r = DeduplicateCorrelateVariables.go(rexBuilder, correlNames.get(0), Util.skip(correlNames), r0);
// Add new node to leaves.
leaves.add(r);
}
return new CorrelationUse(correlNames.get(0), requiredColumns.build(), r);
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method convertUpdate.
private RelNode convertUpdate(SqlUpdate call) {
final SqlValidatorScope scope = validator.getWhereScope(call.getSourceSelect());
Blackboard bb = createBlackboard(scope, null, false);
Builder<RexNode> rexNodeSourceExpressionListBuilder = ImmutableList.builder();
for (SqlNode n : call.getSourceExpressionList()) {
RexNode rn = bb.convertExpression(n);
rexNodeSourceExpressionListBuilder.add(rn);
}
RelOptTable targetTable = getTargetTable(call);
// convert update column list from SqlIdentifier to String
final List<String> targetColumnNameList = new ArrayList<>();
final RelDataType targetRowType = targetTable.getRowType();
for (SqlNode node : call.getTargetColumnList()) {
SqlIdentifier id = (SqlIdentifier) node;
RelDataTypeField field = SqlValidatorUtil.getTargetField(targetRowType, typeFactory, id, catalogReader, targetTable);
assert field != null : "column " + id.toString() + " not found";
targetColumnNameList.add(field.getName());
}
RelNode sourceRel = convertSelect(call.getSourceSelect(), false);
return LogicalTableModify.create(targetTable, catalogReader, sourceRel, LogicalTableModify.Operation.UPDATE, targetColumnNameList, rexNodeSourceExpressionListBuilder.build(), false);
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method convertValues.
/**
* Converts a SELECT statement's parse tree into a relational expression.
*/
public RelNode convertValues(SqlCall values, RelDataType targetRowType) {
final SqlValidatorScope scope = validator.getOverScope(values);
assert scope != null;
final Blackboard bb = createBlackboard(scope, null, false);
convertValuesImpl(bb, values, targetRowType);
return bb.root;
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method isSubQueryNonCorrelated.
/**
* Determines whether a sub-query is non-correlated. Note that a
* non-correlated sub-query can contain correlated references, provided those
* references do not reference select statements that are parents of the
* sub-query.
*
* @param subq the sub-query
* @param bb blackboard used while converting the sub-query, i.e., the
* blackboard of the parent query of this sub-query
* @return true if the sub-query is non-correlated
*/
private boolean isSubQueryNonCorrelated(RelNode subq, Blackboard bb) {
Set<CorrelationId> correlatedVariables = RelOptUtil.getVariablesUsed(subq);
for (CorrelationId correlName : correlatedVariables) {
DeferredLookup lookup = mapCorrelToDeferred.get(correlName);
String originalRelName = lookup.getOriginalRelName();
final SqlNameMatcher nameMatcher = lookup.bb.scope.getValidator().getCatalogReader().nameMatcher();
final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl();
lookup.bb.scope.resolve(ImmutableList.of(originalRelName), nameMatcher, false, resolved);
SqlValidatorScope ancestorScope = resolved.only().scope;
// If the correlated reference is in a scope that's "above" the
// sub-query, then this is a correlated sub-query.
SqlValidatorScope parentScope = bb.scope;
do {
if (ancestorScope == parentScope) {
return false;
}
if (parentScope instanceof DelegatingScope) {
parentScope = ((DelegatingScope) parentScope).getParent();
} else {
break;
}
} while (parentScope != null);
}
return true;
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method convertFrom.
/**
* Converts a FROM clause into a relational expression.
*
* @param bb Scope within which to resolve identifiers
* @param from FROM clause of a query. Examples include:
*
* <ul>
* <li>a single table ("SALES.EMP"),
* <li>an aliased table ("EMP AS E"),
* <li>a list of tables ("EMP, DEPT"),
* <li>an ANSI Join expression ("EMP JOIN DEPT ON EMP.DEPTNO =
* DEPT.DEPTNO"),
* <li>a VALUES clause ("VALUES ('Fred', 20)"),
* <li>a query ("(SELECT * FROM EMP WHERE GENDER = 'F')"),
* <li>or any combination of the above.
* </ul>
*/
protected void convertFrom(Blackboard bb, SqlNode from) {
if (from == null) {
bb.setRoot(LogicalValues.createOneRow(cluster), false);
return;
}
final SqlCall call;
final SqlNode[] operands;
switch(from.getKind()) {
case MATCH_RECOGNIZE:
convertMatchRecognize(bb, (SqlCall) from);
return;
case AS:
call = (SqlCall) from;
convertFrom(bb, call.operand(0));
if (call.operandCount() > 2 && bb.root instanceof Values) {
final List<String> fieldNames = new ArrayList<>();
for (SqlNode node : Util.skip(call.getOperandList(), 2)) {
fieldNames.add(((SqlIdentifier) node).getSimple());
}
bb.setRoot(relBuilder.push(bb.root).rename(fieldNames).build(), true);
}
return;
case WITH_ITEM:
convertFrom(bb, ((SqlWithItem) from).query);
return;
case WITH:
convertFrom(bb, ((SqlWith) from).body);
return;
case TABLESAMPLE:
operands = ((SqlBasicCall) from).getOperands();
SqlSampleSpec sampleSpec = SqlLiteral.sampleValue(operands[1]);
if (sampleSpec instanceof SqlSampleSpec.SqlSubstitutionSampleSpec) {
String sampleName = ((SqlSampleSpec.SqlSubstitutionSampleSpec) sampleSpec).getName();
datasetStack.push(sampleName);
convertFrom(bb, operands[0]);
datasetStack.pop();
} else if (sampleSpec instanceof SqlSampleSpec.SqlTableSampleSpec) {
SqlSampleSpec.SqlTableSampleSpec tableSampleSpec = (SqlSampleSpec.SqlTableSampleSpec) sampleSpec;
convertFrom(bb, operands[0]);
RelOptSamplingParameters params = new RelOptSamplingParameters(tableSampleSpec.isBernoulli(), tableSampleSpec.getSamplePercentage(), tableSampleSpec.isRepeatable(), tableSampleSpec.getRepeatableSeed());
bb.setRoot(new Sample(cluster, bb.root, params), false);
} else {
throw new AssertionError("unknown TABLESAMPLE type: " + sampleSpec);
}
return;
case IDENTIFIER:
convertIdentifier(bb, (SqlIdentifier) from, null);
return;
case EXTEND:
call = (SqlCall) from;
SqlIdentifier id = (SqlIdentifier) call.getOperandList().get(0);
SqlNodeList extendedColumns = (SqlNodeList) call.getOperandList().get(1);
convertIdentifier(bb, id, extendedColumns);
return;
case JOIN:
final SqlJoin join = (SqlJoin) from;
final SqlValidatorScope scope = validator.getJoinScope(from);
final Blackboard fromBlackboard = createBlackboard(scope, null, false);
SqlNode left = join.getLeft();
SqlNode right = join.getRight();
final boolean isNatural = join.isNatural();
final JoinType joinType = join.getJoinType();
final SqlValidatorScope leftScope = Util.first(validator.getJoinScope(left), ((DelegatingScope) bb.scope).getParent());
final Blackboard leftBlackboard = createBlackboard(leftScope, null, false);
final SqlValidatorScope rightScope = Util.first(validator.getJoinScope(right), ((DelegatingScope) bb.scope).getParent());
final Blackboard rightBlackboard = createBlackboard(rightScope, null, false);
convertFrom(leftBlackboard, left);
RelNode leftRel = leftBlackboard.root;
convertFrom(rightBlackboard, right);
RelNode rightRel = rightBlackboard.root;
JoinRelType convertedJoinType = convertJoinType(joinType);
RexNode conditionExp;
final SqlValidatorNamespace leftNamespace = validator.getNamespace(left);
final SqlValidatorNamespace rightNamespace = validator.getNamespace(right);
if (isNatural) {
final RelDataType leftRowType = leftNamespace.getRowType();
final RelDataType rightRowType = rightNamespace.getRowType();
final List<String> columnList = SqlValidatorUtil.deriveNaturalJoinColumnList(leftRowType, rightRowType);
conditionExp = convertUsing(leftNamespace, rightNamespace, columnList);
} else {
conditionExp = convertJoinCondition(fromBlackboard, leftNamespace, rightNamespace, join.getCondition(), join.getConditionType(), leftRel, rightRel);
}
final RelNode joinRel = createJoin(fromBlackboard, leftRel, rightRel, conditionExp, convertedJoinType);
bb.setRoot(joinRel, false);
return;
case SELECT:
case INTERSECT:
case EXCEPT:
case UNION:
final RelNode rel = convertQueryRecursive(from, false, null).project();
bb.setRoot(rel, true);
return;
case VALUES:
convertValuesImpl(bb, (SqlCall) from, null);
return;
case UNNEST:
call = (SqlCall) from;
final List<SqlNode> nodes = call.getOperandList();
final SqlUnnestOperator operator = (SqlUnnestOperator) call.getOperator();
for (SqlNode node : nodes) {
replaceSubQueries(bb, node, RelOptUtil.Logic.TRUE_FALSE_UNKNOWN);
}
final List<RexNode> exprs = new ArrayList<>();
final List<String> fieldNames = new ArrayList<>();
for (Ord<SqlNode> node : Ord.zip(nodes)) {
exprs.add(bb.convertExpression(node.e));
fieldNames.add(validator.deriveAlias(node.e, node.i));
}
RelNode child = (null != bb.root) ? bb.root : LogicalValues.createOneRow(cluster);
relBuilder.push(child).projectNamed(exprs, fieldNames, false);
Uncollect uncollect = new Uncollect(cluster, cluster.traitSetOf(Convention.NONE), relBuilder.build(), operator.withOrdinality);
bb.setRoot(uncollect, true);
return;
case COLLECTION_TABLE:
call = (SqlCall) from;
// Dig out real call; TABLE() wrapper is just syntactic.
assert call.getOperandList().size() == 1;
final SqlCall call2 = call.operand(0);
convertCollectionTable(bb, call2);
return;
default:
throw new AssertionError("not a join operator " + from);
}
}
Aggregations