use of org.apache.calcite.sql.SqlNodeList in project flink by apache.
the class SqlValidatorImpl method rewriteMerge.
private void rewriteMerge(SqlMerge call) {
SqlNodeList selectList;
SqlUpdate updateStmt = call.getUpdateCall();
if (updateStmt != null) {
// if we have an update statement, just clone the select list
// from the update statement's source since it's the same as
// what we want for the select list of the merge source -- '*'
// followed by the update set expressions
selectList = SqlNode.clone(updateStmt.getSourceSelect().getSelectList());
} else {
// otherwise, just use select *
selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
}
SqlNode targetTable = call.getTargetTable();
if (call.getAlias() != null) {
targetTable = SqlValidatorUtil.addAlias(targetTable, call.getAlias().getSimple());
}
// Provided there is an insert substatement, the source select for
// the merge is a left outer join between the source in the USING
// clause and the target table; otherwise, the join is just an
// inner join. Need to clone the source table reference in order
// for validation to work
SqlNode sourceTableRef = call.getSourceTableRef();
SqlInsert insertCall = call.getInsertCall();
JoinType joinType = (insertCall == null) ? JoinType.INNER : JoinType.LEFT;
final SqlNode leftJoinTerm = SqlNode.clone(sourceTableRef);
SqlNode outerJoin = new SqlJoin(SqlParserPos.ZERO, leftJoinTerm, SqlLiteral.createBoolean(false, SqlParserPos.ZERO), joinType.symbol(SqlParserPos.ZERO), targetTable, JoinConditionType.ON.symbol(SqlParserPos.ZERO), call.getCondition());
SqlSelect select = new SqlSelect(SqlParserPos.ZERO, null, selectList, outerJoin, null, null, null, null, null, null, null, null);
call.setSourceSelect(select);
// that via the from clause on the select
if (insertCall != null) {
SqlCall valuesCall = (SqlCall) insertCall.getSource();
SqlCall rowCall = valuesCall.operand(0);
selectList = new SqlNodeList(rowCall.getOperandList(), SqlParserPos.ZERO);
final SqlNode insertSource = SqlNode.clone(sourceTableRef);
select = new SqlSelect(SqlParserPos.ZERO, null, selectList, insertSource, null, null, null, null, null, null, null, null);
insertCall.setSource(select);
}
}
use of org.apache.calcite.sql.SqlNodeList in project flink by apache.
the class SqlValidatorImpl method validateJoin.
protected void validateJoin(SqlJoin join, SqlValidatorScope scope) {
SqlNode left = join.getLeft();
SqlNode right = join.getRight();
SqlNode condition = join.getCondition();
boolean natural = join.isNatural();
final JoinType joinType = join.getJoinType();
final JoinConditionType conditionType = join.getConditionType();
final SqlValidatorScope joinScope = scopes.get(join);
validateFrom(left, unknownType, joinScope);
validateFrom(right, unknownType, joinScope);
// Validate condition.
switch(conditionType) {
case NONE:
Preconditions.checkArgument(condition == null);
break;
case ON:
Preconditions.checkArgument(condition != null);
SqlNode expandedCondition = expand(condition, joinScope);
join.setOperand(5, expandedCondition);
condition = join.getCondition();
validateWhereOrOn(joinScope, condition, "ON");
checkRollUp(null, join, condition, joinScope, "ON");
break;
case USING:
SqlNodeList list = (SqlNodeList) condition;
// Parser ensures that using clause is not empty.
Preconditions.checkArgument(list.size() > 0, "Empty USING clause");
for (SqlNode node : list) {
SqlIdentifier id = (SqlIdentifier) node;
final RelDataType leftColType = validateUsingCol(id, left);
final RelDataType rightColType = validateUsingCol(id, right);
if (!SqlTypeUtil.isComparable(leftColType, rightColType)) {
throw newValidationError(id, RESOURCE.naturalOrUsingColumnNotCompatible(id.getSimple(), leftColType.toString(), rightColType.toString()));
}
checkRollUpInUsing(id, left, scope);
checkRollUpInUsing(id, right, scope);
}
break;
default:
throw Util.unexpected(conditionType);
}
// Validate NATURAL.
if (natural) {
if (condition != null) {
throw newValidationError(condition, RESOURCE.naturalDisallowsOnOrUsing());
}
// Join on fields that occur exactly once on each side. Ignore
// fields that occur more than once on either side.
final RelDataType leftRowType = getNamespace(left).getRowType();
final RelDataType rightRowType = getNamespace(right).getRowType();
final SqlNameMatcher nameMatcher = catalogReader.nameMatcher();
List<String> naturalColumnNames = SqlValidatorUtil.deriveNaturalJoinColumnList(nameMatcher, leftRowType, rightRowType);
// Check compatibility of the chosen columns.
for (String name : naturalColumnNames) {
final RelDataType leftColType = nameMatcher.field(leftRowType, name).getType();
final RelDataType rightColType = nameMatcher.field(rightRowType, name).getType();
if (!SqlTypeUtil.isComparable(leftColType, rightColType)) {
throw newValidationError(join, RESOURCE.naturalOrUsingColumnNotCompatible(name, leftColType.toString(), rightColType.toString()));
}
}
}
// a NATURAL keyword?
switch(joinType) {
case LEFT_SEMI_JOIN:
if (!this.config.sqlConformance().isLiberal()) {
throw newValidationError(join.getJoinTypeNode(), RESOURCE.dialectDoesNotSupportFeature("LEFT SEMI JOIN"));
}
// fall through
case INNER:
case LEFT:
case RIGHT:
case FULL:
if ((condition == null) && !natural) {
throw newValidationError(join, RESOURCE.joinRequiresCondition());
}
break;
case COMMA:
case CROSS:
if (condition != null) {
throw newValidationError(join.getConditionTypeNode(), RESOURCE.crossJoinDisallowsCondition());
}
if (natural) {
throw newValidationError(join.getConditionTypeNode(), RESOURCE.crossJoinDisallowsCondition());
}
break;
default:
throw Util.unexpected(joinType);
}
}
use of org.apache.calcite.sql.SqlNodeList in project flink by apache.
the class SqlValidatorImpl method validateModality.
public boolean validateModality(SqlSelect select, SqlModality modality, boolean fail) {
final SelectScope scope = getRawSelectScope(select);
switch(modality) {
case STREAM:
if (scope.children.size() == 1) {
for (ScopeChild child : scope.children) {
if (!child.namespace.supportsModality(modality)) {
if (fail) {
throw newValidationError(child.namespace.getNode(), Static.RESOURCE.cannotConvertToStream(child.name));
} else {
return false;
}
}
}
} else {
int supportsModalityCount = 0;
for (ScopeChild child : scope.children) {
if (child.namespace.supportsModality(modality)) {
++supportsModalityCount;
}
}
if (supportsModalityCount == 0) {
if (fail) {
String inputs = String.join(", ", scope.getChildNames());
throw newValidationError(select, Static.RESOURCE.cannotStreamResultsForNonStreamingInputs(inputs));
} else {
return false;
}
}
}
break;
default:
for (ScopeChild child : scope.children) {
if (!child.namespace.supportsModality(modality)) {
if (fail) {
throw newValidationError(child.namespace.getNode(), Static.RESOURCE.cannotConvertToRelation(child.name));
} else {
return false;
}
}
}
}
// Make sure that aggregation is possible.
final SqlNode aggregateNode = getAggregate(select);
if (aggregateNode != null) {
switch(modality) {
case STREAM:
SqlNodeList groupList = select.getGroup();
if (groupList == null || !SqlValidatorUtil.containsMonotonic(scope, groupList)) {
if (fail) {
throw newValidationError(aggregateNode, Static.RESOURCE.streamMustGroupByMonotonic());
} else {
return false;
}
}
}
}
// Make sure that ORDER BY is possible.
final SqlNodeList orderList = select.getOrderList();
if (orderList != null && orderList.size() > 0) {
switch(modality) {
case STREAM:
if (!hasSortedPrefix(scope, orderList)) {
if (fail) {
throw newValidationError(orderList.get(0), Static.RESOURCE.streamMustOrderByMonotonic());
} else {
return false;
}
}
}
}
return true;
}
use of org.apache.calcite.sql.SqlNodeList in project flink by apache.
the class SqlValidatorImpl method expandExprFromJoin.
private static SqlNode expandExprFromJoin(SqlJoin join, SqlIdentifier identifier, SelectScope scope) {
if (join.getConditionType() != JoinConditionType.USING) {
return identifier;
}
for (SqlNode node : (SqlNodeList) join.getCondition()) {
final String name = ((SqlIdentifier) node).getSimple();
if (identifier.getSimple().equals(name)) {
final List<SqlNode> qualifiedNode = new ArrayList<>();
for (ScopeChild child : scope.children) {
if (child.namespace.getRowType().getFieldNames().indexOf(name) >= 0) {
final SqlIdentifier exp = new SqlIdentifier(ImmutableList.of(child.name, name), identifier.getParserPosition());
qualifiedNode.add(exp);
}
}
assert qualifiedNode.size() == 2;
final SqlNode finalNode = SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, SqlStdOperatorTable.COALESCE.createCall(SqlParserPos.ZERO, qualifiedNode.get(0), qualifiedNode.get(1)), new SqlIdentifier(name, SqlParserPos.ZERO));
return finalNode;
}
}
// Only need to try to expand the expr from the left input of join
// since it is always left-deep join.
final SqlNode node = join.getLeft();
if (node instanceof SqlJoin) {
return expandExprFromJoin((SqlJoin) node, identifier, scope);
} else {
return identifier;
}
}
use of org.apache.calcite.sql.SqlNodeList in project flink by apache.
the class SqlValidatorImpl method validateDefinitions.
private void validateDefinitions(SqlMatchRecognize mr, MatchRecognizeScope scope) {
final Set<String> aliases = catalogReader.nameMatcher().createSet();
for (SqlNode item : mr.getPatternDefList().getList()) {
final String alias = alias(item);
if (!aliases.add(alias)) {
throw newValidationError(item, Static.RESOURCE.patternVarAlreadyDefined(alias));
}
scope.addPatternVar(alias);
}
final List<SqlNode> sqlNodes = new ArrayList<>();
for (SqlNode item : mr.getPatternDefList().getList()) {
final String alias = alias(item);
SqlNode expand = expand(item, scope);
expand = navigationInDefine(expand, alias);
setOriginal(expand, item);
inferUnknownTypes(booleanType, scope, expand);
expand.validate(this, scope);
// Some extra work need required here.
// In PREV, NEXT, FINAL and LAST, only one pattern variable is allowed.
sqlNodes.add(SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, expand, new SqlIdentifier(alias, SqlParserPos.ZERO)));
final RelDataType type = deriveType(scope, expand);
if (!SqlTypeUtil.inBooleanFamily(type)) {
throw newValidationError(expand, RESOURCE.condMustBeBoolean("DEFINE"));
}
setValidatedNodeType(item, type);
}
SqlNodeList list = new SqlNodeList(sqlNodes, mr.getPatternDefList().getParserPosition());
inferUnknownTypes(unknownType, scope, list);
for (SqlNode node : list) {
validateExpr(node, scope);
}
mr.setOperand(SqlMatchRecognize.OPERAND_PATTERN_DEFINES, list);
}
Aggregations