use of org.apache.calcite.sql.SqlUpdate 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.SqlUpdate in project hazelcast by hazelcast.
the class HazelcastTypeCoercion method coerceSourceRowType.
// originally copied from TypeCoercionImpl
private boolean coerceSourceRowType(SqlValidatorScope sourceScope, SqlNode query, int columnIndex, int totalColumns, RelDataType targetType) {
switch(query.getKind()) {
case INSERT:
SqlInsert insert = (SqlInsert) query;
return coerceSourceRowType(sourceScope, insert.getSource(), columnIndex, totalColumns, targetType);
case UPDATE:
// trailing elements of selectList are equal to elements of sourceExpressionList
// see JetSqlValidator.validateUpdate()
SqlUpdate update = (SqlUpdate) query;
SqlNodeList selectList = update.getSourceSelect().getSelectList();
return coerceSourceRowType(sourceScope, selectList, selectList.size() - totalColumns + columnIndex, targetType);
default:
return rowTypeCoercion(sourceScope, query, columnIndex, targetType);
}
}
use of org.apache.calcite.sql.SqlUpdate 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.SqlUpdate 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.SqlUpdate in project flink by apache.
the class SqlValidatorImpl method checkTypeAssignment.
/**
* Checks the type assignment of an INSERT or UPDATE query.
*
* <p>Skip the virtual columns(can not insert into) type assignment check if the source fields
* count equals with the real target table fields count, see how #checkFieldCount was used.
*
* @param sourceScope Scope of query source which is used to infer node type
* @param table Target table
* @param sourceRowType Source row type
* @param targetRowType Target row type, it should either contain all the virtual columns (can
* not insert into) or exclude all the virtual columns
* @param query The query
*/
protected void checkTypeAssignment(SqlValidatorScope sourceScope, SqlValidatorTable table, RelDataType sourceRowType, RelDataType targetRowType, final SqlNode query) {
// NOTE jvs 23-Feb-2006: subclasses may allow for extra targets
// representing system-maintained columns, so stop after all sources
// matched
boolean isUpdateModifiableViewTable = false;
if (query instanceof SqlUpdate) {
final SqlNodeList targetColumnList = ((SqlUpdate) query).getTargetColumnList();
if (targetColumnList != null) {
final int targetColumnCnt = targetColumnList.size();
targetRowType = SqlTypeUtil.extractLastNFields(typeFactory, targetRowType, targetColumnCnt);
sourceRowType = SqlTypeUtil.extractLastNFields(typeFactory, sourceRowType, targetColumnCnt);
}
isUpdateModifiableViewTable = table.unwrap(ModifiableViewTable.class) != null;
}
if (SqlTypeUtil.equalAsStructSansNullability(typeFactory, sourceRowType, targetRowType, null)) {
// Returns early if source and target row type equals sans nullability.
return;
}
if (config.typeCoercionEnabled() && !isUpdateModifiableViewTable) {
// Try type coercion first if implicit type coercion is allowed.
boolean coerced = typeCoercion.querySourceCoercion(sourceScope, sourceRowType, targetRowType, query);
if (coerced) {
return;
}
}
// Fall back to default behavior: compare the type families.
List<RelDataTypeField> sourceFields = sourceRowType.getFieldList();
List<RelDataTypeField> targetFields = targetRowType.getFieldList();
final int sourceCount = sourceFields.size();
for (int i = 0; i < sourceCount; ++i) {
RelDataType sourceType = sourceFields.get(i).getType();
RelDataType targetType = targetFields.get(i).getType();
if (!SqlTypeUtil.canAssignFrom(targetType, sourceType)) {
SqlNode node = getNthExpr(query, i, sourceCount);
if (node instanceof SqlDynamicParam) {
continue;
}
String targetTypeString;
String sourceTypeString;
if (SqlTypeUtil.areCharacterSetsMismatched(sourceType, targetType)) {
sourceTypeString = sourceType.getFullTypeString();
targetTypeString = targetType.getFullTypeString();
} else {
sourceTypeString = sourceType.toString();
targetTypeString = targetType.toString();
}
throw newValidationError(node, RESOURCE.typeNotAssignable(targetFields.get(i).getName(), targetTypeString, sourceFields.get(i).getName(), sourceTypeString));
}
}
}
Aggregations