use of org.apache.calcite.sql.SqlMerge in project calcite by apache.
the class SqlValidatorImpl method performUnconditionalRewrites.
/**
* Performs expression rewrites which are always used unconditionally. These
* rewrites massage the expression tree into a standard form so that the
* rest of the validation logic can be simpler.
*
* @param node expression to be rewritten
* @param underFrom whether node appears directly under a FROM clause
* @return rewritten expression
*/
protected SqlNode performUnconditionalRewrites(SqlNode node, boolean underFrom) {
if (node == null) {
return node;
}
SqlNode newOperand;
// first transform operands and invoke generic call rewrite
if (node instanceof SqlCall) {
if (node instanceof SqlMerge) {
validatingSqlMerge = true;
}
SqlCall call = (SqlCall) node;
final SqlKind kind = call.getKind();
final List<SqlNode> operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
SqlNode operand = operands.get(i);
boolean childUnderFrom;
if (kind == SqlKind.SELECT) {
childUnderFrom = i == SqlSelect.FROM_OPERAND;
} else if (kind == SqlKind.AS && (i == 0)) {
// for an aliased expression, it is under FROM if
// the AS expression is under FROM
childUnderFrom = underFrom;
} else {
childUnderFrom = false;
}
newOperand = performUnconditionalRewrites(operand, childUnderFrom);
if (newOperand != null && newOperand != operand) {
call.setOperand(i, newOperand);
}
}
if (call.getOperator() instanceof SqlUnresolvedFunction) {
assert call instanceof SqlBasicCall;
final SqlUnresolvedFunction function = (SqlUnresolvedFunction) call.getOperator();
// This function hasn't been resolved yet. Perform
// a half-hearted resolution now in case it's a
// builtin function requiring special casing. If it's
// not, we'll handle it later during overload resolution.
final List<SqlOperator> overloads = new ArrayList<>();
opTab.lookupOperatorOverloads(function.getNameAsId(), function.getFunctionType(), SqlSyntax.FUNCTION, overloads);
if (overloads.size() == 1) {
((SqlBasicCall) call).setOperator(overloads.get(0));
}
}
if (rewriteCalls) {
node = call.getOperator().rewriteCall(this, call);
}
} else if (node instanceof SqlNodeList) {
SqlNodeList list = (SqlNodeList) node;
for (int i = 0, count = list.size(); i < count; i++) {
SqlNode operand = list.get(i);
newOperand = performUnconditionalRewrites(operand, false);
if (newOperand != null) {
list.getList().set(i, newOperand);
}
}
}
// now transform node itself
final SqlKind kind = node.getKind();
switch(kind) {
case VALUES:
// CHECKSTYLE: IGNORE 1
if (underFrom || true) {
// over and over
return node;
} else {
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
return new SqlSelect(node.getParserPosition(), null, selectList, node, null, null, null, null, null, null, null);
}
case ORDER_BY:
{
SqlOrderBy orderBy = (SqlOrderBy) node;
handleOffsetFetch(orderBy.offset, orderBy.fetch);
if (orderBy.query instanceof SqlSelect) {
SqlSelect select = (SqlSelect) orderBy.query;
// an order-sensitive function like RANK.
if (select.getOrderList() == null) {
// push ORDER BY into existing select
select.setOrderBy(orderBy.orderList);
select.setOffset(orderBy.offset);
select.setFetch(orderBy.fetch);
return select;
}
}
if (orderBy.query instanceof SqlWith && ((SqlWith) orderBy.query).body instanceof SqlSelect) {
SqlWith with = (SqlWith) orderBy.query;
SqlSelect select = (SqlSelect) with.body;
// an order-sensitive function like RANK.
if (select.getOrderList() == null) {
// push ORDER BY into existing select
select.setOrderBy(orderBy.orderList);
select.setOffset(orderBy.offset);
select.setFetch(orderBy.fetch);
return with;
}
}
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
final SqlNodeList orderList;
if (getInnerSelect(node) != null && isAggregate(getInnerSelect(node))) {
orderList = SqlNode.clone(orderBy.orderList);
// We assume that ORDER BY item is present in SELECT list.
for (int i = 0; i < orderList.size(); i++) {
SqlNode sqlNode = orderList.get(i);
SqlNodeList selectList2 = getInnerSelect(node).getSelectList();
for (Ord<SqlNode> sel : Ord.zip(selectList2)) {
if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) {
orderList.set(i, SqlLiteral.createExactNumeric(Integer.toString(sel.i + 1), SqlParserPos.ZERO));
}
}
}
} else {
orderList = orderBy.orderList;
}
return new SqlSelect(SqlParserPos.ZERO, null, selectList, orderBy.query, null, null, null, null, orderList, orderBy.offset, orderBy.fetch);
}
case EXPLICIT_TABLE:
{
// (TABLE t) is equivalent to (SELECT * FROM t)
SqlCall call = (SqlCall) node;
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
return new SqlSelect(SqlParserPos.ZERO, null, selectList, call.operand(0), null, null, null, null, null, null, null);
}
case DELETE:
{
SqlDelete call = (SqlDelete) node;
SqlSelect select = createSourceSelectForDelete(call);
call.setSourceSelect(select);
break;
}
case UPDATE:
{
SqlUpdate call = (SqlUpdate) node;
SqlSelect select = createSourceSelectForUpdate(call);
call.setSourceSelect(select);
// in which case leave it alone).
if (!validatingSqlMerge) {
SqlNode selfJoinSrcExpr = getSelfJoinExprForUpdate(call.getTargetTable(), UPDATE_SRC_ALIAS);
if (selfJoinSrcExpr != null) {
node = rewriteUpdateToMerge(call, selfJoinSrcExpr);
}
}
break;
}
case MERGE:
{
SqlMerge call = (SqlMerge) node;
rewriteMerge(call);
break;
}
}
return node;
}
use of org.apache.calcite.sql.SqlMerge in project calcite by apache.
the class SqlValidatorImpl method registerQuery.
/**
* Registers a query in a parent scope.
*
* @param parentScope Parent scope which this scope turns to in order to
* resolve objects
* @param usingScope Scope whose child list this scope should add itself to
* @param node Query node
* @param alias Name of this query within its parent. Must be specified
* if usingScope != null
* @param checkUpdate if true, validate that the update feature is supported
* if validating the update statement
*/
private void registerQuery(SqlValidatorScope parentScope, SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, String alias, boolean forceNullable, boolean checkUpdate) {
Preconditions.checkNotNull(node);
Preconditions.checkNotNull(enclosingNode);
Preconditions.checkArgument(usingScope == null || alias != null);
SqlCall call;
List<SqlNode> operands;
switch(node.getKind()) {
case SELECT:
final SqlSelect select = (SqlSelect) node;
final SelectNamespace selectNs = createSelectNamespace(select, enclosingNode);
registerNamespace(usingScope, alias, selectNs, forceNullable);
final SqlValidatorScope windowParentScope = (usingScope != null) ? usingScope : parentScope;
SelectScope selectScope = new SelectScope(parentScope, windowParentScope, select);
scopes.put(select, selectScope);
// Start by registering the WHERE clause
whereScopes.put(select, selectScope);
registerOperandSubQueries(selectScope, select, SqlSelect.WHERE_OPERAND);
// Register FROM with the inherited scope 'parentScope', not
// 'selectScope', otherwise tables in the FROM clause would be
// able to see each other.
final SqlNode from = select.getFrom();
if (from != null) {
final SqlNode newFrom = registerFrom(parentScope, selectScope, from, from, null, null, false);
if (newFrom != from) {
select.setFrom(newFrom);
}
}
// If this is an aggregating query, the SELECT list and HAVING
// clause use a different scope, where you can only reference
// columns which are in the GROUP BY clause.
SqlValidatorScope aggScope = selectScope;
if (isAggregate(select)) {
aggScope = new AggregatingSelectScope(selectScope, select, false);
selectScopes.put(select, aggScope);
} else {
selectScopes.put(select, selectScope);
}
if (select.getGroup() != null) {
GroupByScope groupByScope = new GroupByScope(selectScope, select.getGroup(), select);
groupByScopes.put(select, groupByScope);
registerSubQueries(groupByScope, select.getGroup());
}
registerOperandSubQueries(aggScope, select, SqlSelect.HAVING_OPERAND);
registerSubQueries(aggScope, select.getSelectList());
final SqlNodeList orderList = select.getOrderList();
if (orderList != null) {
// available to the ORDER BY clause.
if (select.isDistinct()) {
aggScope = new AggregatingSelectScope(selectScope, select, true);
}
OrderByScope orderScope = new OrderByScope(aggScope, orderList, select);
orderScopes.put(select, orderScope);
registerSubQueries(orderScope, orderList);
if (!isAggregate(select)) {
// Since this is not an aggregating query,
// there cannot be any aggregates in the ORDER BY clause.
SqlNode agg = aggFinder.findAgg(orderList);
if (agg != null) {
throw newValidationError(agg, RESOURCE.aggregateIllegalInOrderBy());
}
}
}
break;
case INTERSECT:
validateFeature(RESOURCE.sQLFeature_F302(), node.getParserPosition());
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case EXCEPT:
validateFeature(RESOURCE.sQLFeature_E071_03(), node.getParserPosition());
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case UNION:
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case WITH:
registerWith(parentScope, usingScope, (SqlWith) node, enclosingNode, alias, forceNullable, checkUpdate);
break;
case VALUES:
call = (SqlCall) node;
scopes.put(call, parentScope);
final TableConstructorNamespace tableConstructorNamespace = new TableConstructorNamespace(this, call, parentScope, enclosingNode);
registerNamespace(usingScope, alias, tableConstructorNamespace, forceNullable);
operands = call.getOperandList();
for (int i = 0; i < operands.size(); ++i) {
assert operands.get(i).getKind() == SqlKind.ROW;
// FIXME jvs 9-Feb-2005: Correlation should
// be illegal in these sub-queries. Same goes for
// any non-lateral SELECT in the FROM list.
registerOperandSubQueries(parentScope, call, i);
}
break;
case INSERT:
SqlInsert insertCall = (SqlInsert) node;
InsertNamespace insertNs = new InsertNamespace(this, insertCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, insertNs, forceNullable);
registerQuery(parentScope, usingScope, insertCall.getSource(), enclosingNode, null, false);
break;
case DELETE:
SqlDelete deleteCall = (SqlDelete) node;
DeleteNamespace deleteNs = new DeleteNamespace(this, deleteCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, deleteNs, forceNullable);
registerQuery(parentScope, usingScope, deleteCall.getSourceSelect(), enclosingNode, null, false);
break;
case UPDATE:
if (checkUpdate) {
validateFeature(RESOURCE.sQLFeature_E101_03(), node.getParserPosition());
}
SqlUpdate updateCall = (SqlUpdate) node;
UpdateNamespace updateNs = new UpdateNamespace(this, updateCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, updateNs, forceNullable);
registerQuery(parentScope, usingScope, updateCall.getSourceSelect(), enclosingNode, null, false);
break;
case MERGE:
validateFeature(RESOURCE.sQLFeature_F312(), node.getParserPosition());
SqlMerge mergeCall = (SqlMerge) node;
MergeNamespace mergeNs = new MergeNamespace(this, mergeCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, mergeNs, forceNullable);
registerQuery(parentScope, usingScope, mergeCall.getSourceSelect(), enclosingNode, null, false);
// validation check
if (mergeCall.getUpdateCall() != null) {
registerQuery(whereScopes.get(mergeCall.getSourceSelect()), null, mergeCall.getUpdateCall(), enclosingNode, null, false, false);
}
if (mergeCall.getInsertCall() != null) {
registerQuery(parentScope, null, mergeCall.getInsertCall(), enclosingNode, null, false);
}
break;
case UNNEST:
call = (SqlCall) node;
final UnnestNamespace unnestNs = new UnnestNamespace(this, call, parentScope, enclosingNode);
registerNamespace(usingScope, alias, unnestNs, forceNullable);
registerOperandSubQueries(parentScope, call, 0);
scopes.put(node, parentScope);
break;
case OTHER_FUNCTION:
call = (SqlCall) node;
ProcedureNamespace procNs = new ProcedureNamespace(this, parentScope, call, enclosingNode);
registerNamespace(usingScope, alias, procNs, forceNullable);
registerSubQueries(parentScope, call);
break;
case MULTISET_QUERY_CONSTRUCTOR:
case MULTISET_VALUE_CONSTRUCTOR:
validateFeature(RESOURCE.sQLFeature_S271(), node.getParserPosition());
call = (SqlCall) node;
CollectScope cs = new CollectScope(parentScope, usingScope, call);
final CollectNamespace tableConstructorNs = new CollectNamespace(call, cs, enclosingNode);
final String alias2 = deriveAlias(node, nextGeneratedId++);
registerNamespace(usingScope, alias2, tableConstructorNs, forceNullable);
operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
registerOperandSubQueries(parentScope, call, i);
}
break;
default:
throw Util.unexpected(node.getKind());
}
}
use of org.apache.calcite.sql.SqlMerge in project flink by apache.
the class SqlValidatorImpl method performUnconditionalRewrites.
/**
* Performs expression rewrites which are always used unconditionally. These rewrites massage
* the expression tree into a standard form so that the rest of the validation logic can be
* simpler.
*
* @param node expression to be rewritten
* @param underFrom whether node appears directly under a FROM clause
* @return rewritten expression
*/
protected SqlNode performUnconditionalRewrites(SqlNode node, boolean underFrom) {
if (node == null) {
return null;
}
SqlNode newOperand;
// first transform operands and invoke generic call rewrite
if (node instanceof SqlCall) {
if (node instanceof SqlMerge) {
validatingSqlMerge = true;
}
SqlCall call = (SqlCall) node;
final SqlKind kind = call.getKind();
final List<SqlNode> operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
SqlNode operand = operands.get(i);
boolean childUnderFrom;
if (kind == SqlKind.SELECT) {
childUnderFrom = i == SqlSelect.FROM_OPERAND;
} else if (kind == SqlKind.AS && (i == 0)) {
// for an aliased expression, it is under FROM if
// the AS expression is under FROM
childUnderFrom = underFrom;
} else {
childUnderFrom = false;
}
newOperand = performUnconditionalRewrites(operand, childUnderFrom);
if (newOperand != null && newOperand != operand) {
call.setOperand(i, newOperand);
}
}
if (call.getOperator() instanceof SqlUnresolvedFunction) {
assert call instanceof SqlBasicCall;
final SqlUnresolvedFunction function = (SqlUnresolvedFunction) call.getOperator();
// This function hasn't been resolved yet. Perform
// a half-hearted resolution now in case it's a
// builtin function requiring special casing. If it's
// not, we'll handle it later during overload resolution.
final List<SqlOperator> overloads = new ArrayList<>();
opTab.lookupOperatorOverloads(function.getNameAsId(), function.getFunctionType(), SqlSyntax.FUNCTION, overloads, catalogReader.nameMatcher());
if (overloads.size() == 1) {
((SqlBasicCall) call).setOperator(overloads.get(0));
}
}
if (config.callRewrite()) {
node = call.getOperator().rewriteCall(this, call);
}
} else if (node instanceof SqlNodeList) {
SqlNodeList list = (SqlNodeList) node;
for (int i = 0, count = list.size(); i < count; i++) {
SqlNode operand = list.get(i);
newOperand = performUnconditionalRewrites(operand, false);
if (newOperand != null) {
list.getList().set(i, newOperand);
}
}
}
// now transform node itself
final SqlKind kind = node.getKind();
switch(kind) {
case VALUES:
// CHECKSTYLE: IGNORE 1
if (underFrom || true) {
// over and over
return node;
} else {
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
return new SqlSelect(node.getParserPosition(), null, selectList, node, null, null, null, null, null, null, null, null);
}
case ORDER_BY:
{
SqlOrderBy orderBy = (SqlOrderBy) node;
handleOffsetFetch(orderBy.offset, orderBy.fetch);
if (orderBy.query instanceof SqlSelect) {
SqlSelect select = (SqlSelect) orderBy.query;
// an order-sensitive function like RANK.
if (select.getOrderList() == null) {
// push ORDER BY into existing select
select.setOrderBy(orderBy.orderList);
select.setOffset(orderBy.offset);
select.setFetch(orderBy.fetch);
return select;
}
}
if (orderBy.query instanceof SqlWith && ((SqlWith) orderBy.query).body instanceof SqlSelect) {
SqlWith with = (SqlWith) orderBy.query;
SqlSelect select = (SqlSelect) with.body;
// an order-sensitive function like RANK.
if (select.getOrderList() == null) {
// push ORDER BY into existing select
select.setOrderBy(orderBy.orderList);
select.setOffset(orderBy.offset);
select.setFetch(orderBy.fetch);
return with;
}
}
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
final SqlNodeList orderList;
if (getInnerSelect(node) != null && isAggregate(getInnerSelect(node))) {
orderList = SqlNode.clone(orderBy.orderList);
// We assume that ORDER BY item is present in SELECT list.
for (int i = 0; i < orderList.size(); i++) {
SqlNode sqlNode = orderList.get(i);
SqlNodeList selectList2 = getInnerSelect(node).getSelectList();
for (Ord<SqlNode> sel : Ord.zip(selectList2)) {
if (stripAs(sel.e).equalsDeep(sqlNode, Litmus.IGNORE)) {
orderList.set(i, SqlLiteral.createExactNumeric(Integer.toString(sel.i + 1), SqlParserPos.ZERO));
}
}
}
} else {
orderList = orderBy.orderList;
}
return new SqlSelect(SqlParserPos.ZERO, null, selectList, orderBy.query, null, null, null, null, orderList, orderBy.offset, orderBy.fetch, null);
}
case EXPLICIT_TABLE:
{
// (TABLE t) is equivalent to (SELECT * FROM t)
SqlCall call = (SqlCall) node;
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
selectList.add(SqlIdentifier.star(SqlParserPos.ZERO));
return new SqlSelect(SqlParserPos.ZERO, null, selectList, call.operand(0), null, null, null, null, null, null, null, null);
}
case DELETE:
{
SqlDelete call = (SqlDelete) node;
SqlSelect select = createSourceSelectForDelete(call);
call.setSourceSelect(select);
break;
}
case UPDATE:
{
SqlUpdate call = (SqlUpdate) node;
SqlSelect select = createSourceSelectForUpdate(call);
call.setSourceSelect(select);
// in which case leave it alone).
if (!validatingSqlMerge) {
SqlNode selfJoinSrcExpr = getSelfJoinExprForUpdate(call.getTargetTable(), UPDATE_SRC_ALIAS);
if (selfJoinSrcExpr != null) {
node = rewriteUpdateToMerge(call, selfJoinSrcExpr);
}
}
break;
}
case MERGE:
{
SqlMerge call = (SqlMerge) node;
rewriteMerge(call);
break;
}
}
return node;
}
use of org.apache.calcite.sql.SqlMerge in project flink by apache.
the class SqlValidatorImpl method registerQuery.
/**
* Registers a query in a parent scope.
*
* @param parentScope Parent scope which this scope turns to in order to resolve objects
* @param usingScope Scope whose child list this scope should add itself to
* @param node Query node
* @param alias Name of this query within its parent. Must be specified if usingScope != null
* @param checkUpdate if true, validate that the update feature is supported if validating the
* update statement
*/
private void registerQuery(SqlValidatorScope parentScope, SqlValidatorScope usingScope, SqlNode node, SqlNode enclosingNode, String alias, boolean forceNullable, boolean checkUpdate) {
Objects.requireNonNull(node);
Objects.requireNonNull(enclosingNode);
Preconditions.checkArgument(usingScope == null || alias != null);
SqlCall call;
List<SqlNode> operands;
switch(node.getKind()) {
case SELECT:
final SqlSelect select = (SqlSelect) node;
final SelectNamespace selectNs = createSelectNamespace(select, enclosingNode);
registerNamespace(usingScope, alias, selectNs, forceNullable);
final SqlValidatorScope windowParentScope = (usingScope != null) ? usingScope : parentScope;
SelectScope selectScope = new SelectScope(parentScope, windowParentScope, select);
scopes.put(select, selectScope);
// Start by registering the WHERE clause
clauseScopes.put(IdPair.of(select, Clause.WHERE), selectScope);
registerOperandSubQueries(selectScope, select, SqlSelect.WHERE_OPERAND);
// Register FROM with the inherited scope 'parentScope', not
// 'selectScope', otherwise tables in the FROM clause would be
// able to see each other.
final SqlNode from = select.getFrom();
if (from != null) {
final SqlNode newFrom = registerFrom(parentScope, selectScope, true, from, from, null, null, false, false);
if (newFrom != from) {
select.setFrom(newFrom);
}
}
// If this is an aggregating query, the SELECT list and HAVING
// clause use a different scope, where you can only reference
// columns which are in the GROUP BY clause.
SqlValidatorScope aggScope = selectScope;
if (isAggregate(select)) {
aggScope = new AggregatingSelectScope(selectScope, select, false);
clauseScopes.put(IdPair.of(select, Clause.SELECT), aggScope);
} else {
clauseScopes.put(IdPair.of(select, Clause.SELECT), selectScope);
}
if (select.getGroup() != null) {
GroupByScope groupByScope = new GroupByScope(selectScope, select.getGroup(), select);
clauseScopes.put(IdPair.of(select, Clause.GROUP_BY), groupByScope);
registerSubQueries(groupByScope, select.getGroup());
}
registerOperandSubQueries(aggScope, select, SqlSelect.HAVING_OPERAND);
registerSubQueries(aggScope, select.getSelectList());
final SqlNodeList orderList = select.getOrderList();
if (orderList != null) {
// available to the ORDER BY clause.
if (select.isDistinct()) {
aggScope = new AggregatingSelectScope(selectScope, select, true);
}
OrderByScope orderScope = new OrderByScope(aggScope, orderList, select);
clauseScopes.put(IdPair.of(select, Clause.ORDER), orderScope);
registerSubQueries(orderScope, orderList);
if (!isAggregate(select)) {
// Since this is not an aggregating query,
// there cannot be any aggregates in the ORDER BY clause.
SqlNode agg = aggFinder.findAgg(orderList);
if (agg != null) {
throw newValidationError(agg, RESOURCE.aggregateIllegalInOrderBy());
}
}
}
break;
case INTERSECT:
validateFeature(RESOURCE.sQLFeature_F302(), node.getParserPosition());
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case EXCEPT:
validateFeature(RESOURCE.sQLFeature_E071_03(), node.getParserPosition());
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case UNION:
registerSetop(parentScope, usingScope, node, node, alias, forceNullable);
break;
case WITH:
registerWith(parentScope, usingScope, (SqlWith) node, enclosingNode, alias, forceNullable, checkUpdate);
break;
case VALUES:
call = (SqlCall) node;
scopes.put(call, parentScope);
final TableConstructorNamespace tableConstructorNamespace = new TableConstructorNamespace(this, call, parentScope, enclosingNode);
registerNamespace(usingScope, alias, tableConstructorNamespace, forceNullable);
operands = call.getOperandList();
for (int i = 0; i < operands.size(); ++i) {
assert operands.get(i).getKind() == SqlKind.ROW;
// FIXME jvs 9-Feb-2005: Correlation should
// be illegal in these sub-queries. Same goes for
// any non-lateral SELECT in the FROM list.
registerOperandSubQueries(parentScope, call, i);
}
break;
case INSERT:
SqlInsert insertCall = (SqlInsert) node;
InsertNamespace insertNs = new InsertNamespace(this, insertCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, insertNs, forceNullable);
registerQuery(parentScope, usingScope, insertCall.getSource(), enclosingNode, null, false);
break;
case DELETE:
SqlDelete deleteCall = (SqlDelete) node;
DeleteNamespace deleteNs = new DeleteNamespace(this, deleteCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, deleteNs, forceNullable);
registerQuery(parentScope, usingScope, deleteCall.getSourceSelect(), enclosingNode, null, false);
break;
case UPDATE:
if (checkUpdate) {
validateFeature(RESOURCE.sQLFeature_E101_03(), node.getParserPosition());
}
SqlUpdate updateCall = (SqlUpdate) node;
UpdateNamespace updateNs = new UpdateNamespace(this, updateCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, updateNs, forceNullable);
registerQuery(parentScope, usingScope, updateCall.getSourceSelect(), enclosingNode, null, false);
break;
case MERGE:
validateFeature(RESOURCE.sQLFeature_F312(), node.getParserPosition());
SqlMerge mergeCall = (SqlMerge) node;
MergeNamespace mergeNs = new MergeNamespace(this, mergeCall, enclosingNode, parentScope);
registerNamespace(usingScope, null, mergeNs, forceNullable);
registerQuery(parentScope, usingScope, mergeCall.getSourceSelect(), enclosingNode, null, false);
// validation check
if (mergeCall.getUpdateCall() != null) {
registerQuery(clauseScopes.get(IdPair.of(mergeCall.getSourceSelect(), Clause.WHERE)), null, mergeCall.getUpdateCall(), enclosingNode, null, false, false);
}
if (mergeCall.getInsertCall() != null) {
registerQuery(parentScope, null, mergeCall.getInsertCall(), enclosingNode, null, false);
}
break;
case UNNEST:
call = (SqlCall) node;
final UnnestNamespace unnestNs = new UnnestNamespace(this, call, parentScope, enclosingNode);
registerNamespace(usingScope, alias, unnestNs, forceNullable);
registerOperandSubQueries(parentScope, call, 0);
scopes.put(node, parentScope);
break;
case OTHER_FUNCTION:
call = (SqlCall) node;
ProcedureNamespace procNs = new ProcedureNamespace(this, parentScope, call, enclosingNode);
registerNamespace(usingScope, alias, procNs, forceNullable);
registerSubQueries(parentScope, call);
break;
case MULTISET_QUERY_CONSTRUCTOR:
case MULTISET_VALUE_CONSTRUCTOR:
validateFeature(RESOURCE.sQLFeature_S271(), node.getParserPosition());
call = (SqlCall) node;
CollectScope cs = new CollectScope(parentScope, usingScope, call);
final CollectNamespace tableConstructorNs = new CollectNamespace(call, cs, enclosingNode);
final String alias2 = deriveAlias(node, nextGeneratedId++);
registerNamespace(usingScope, alias2, tableConstructorNs, forceNullable);
operands = call.getOperandList();
for (int i = 0; i < operands.size(); i++) {
registerOperandSubQueries(parentScope, call, i);
}
break;
default:
throw Util.unexpected(node.getKind());
}
}
use of org.apache.calcite.sql.SqlMerge in project flink by apache.
the class SqlValidatorImpl method rewriteUpdateToMerge.
private SqlNode rewriteUpdateToMerge(SqlUpdate updateCall, SqlNode selfJoinSrcExpr) {
// Make sure target has an alias.
if (updateCall.getAlias() == null) {
updateCall.setAlias(new SqlIdentifier(UPDATE_TGT_ALIAS, SqlParserPos.ZERO));
}
SqlNode selfJoinTgtExpr = getSelfJoinExprForUpdate(updateCall.getTargetTable(), updateCall.getAlias().getSimple());
assert selfJoinTgtExpr != null;
// Create join condition between source and target exprs,
// creating a conjunction with the user-level WHERE
// clause if one was supplied
SqlNode condition = updateCall.getCondition();
SqlNode selfJoinCond = SqlStdOperatorTable.EQUALS.createCall(SqlParserPos.ZERO, selfJoinSrcExpr, selfJoinTgtExpr);
if (condition == null) {
condition = selfJoinCond;
} else {
condition = SqlStdOperatorTable.AND.createCall(SqlParserPos.ZERO, selfJoinCond, condition);
}
SqlNode target = updateCall.getTargetTable().clone(SqlParserPos.ZERO);
// For the source, we need to anonymize the fields, so
// that for a statement like UPDATE T SET I = I + 1,
// there's no ambiguity for the "I" in "I + 1";
// this is OK because the source and target have
// identical values due to the self-join.
// Note that we anonymize the source rather than the
// target because downstream, the optimizer rules
// don't want to see any projection on top of the target.
IdentifierNamespace ns = new IdentifierNamespace(this, target, null, null);
RelDataType rowType = ns.getRowType();
SqlNode source = updateCall.getTargetTable().clone(SqlParserPos.ZERO);
final SqlNodeList selectList = new SqlNodeList(SqlParserPos.ZERO);
int i = 1;
for (RelDataTypeField field : rowType.getFieldList()) {
SqlIdentifier col = new SqlIdentifier(field.getName(), SqlParserPos.ZERO);
selectList.add(SqlValidatorUtil.addAlias(col, UPDATE_ANON_PREFIX + i));
++i;
}
source = new SqlSelect(SqlParserPos.ZERO, null, selectList, source, null, null, null, null, null, null, null, null);
source = SqlValidatorUtil.addAlias(source, UPDATE_SRC_ALIAS);
SqlMerge mergeCall = new SqlMerge(updateCall.getParserPosition(), target, condition, source, updateCall, null, null, updateCall.getAlias());
rewriteMerge(mergeCall);
return mergeCall;
}
Aggregations