use of org.apache.calcite.sql.SqlCall in project calcite by apache.
the class SqlValidatorImpl method validateValues.
/**
* Validates a VALUES clause.
*
* @param node Values clause
* @param targetRowType Row type which expression must conform to
* @param scope Scope within which clause occurs
*/
protected void validateValues(SqlCall node, RelDataType targetRowType, final SqlValidatorScope scope) {
assert node.getKind() == SqlKind.VALUES;
final List<SqlNode> operands = node.getOperandList();
for (SqlNode operand : operands) {
if (!(operand.getKind() == SqlKind.ROW)) {
throw Util.needToImplement("Values function where operands are scalars");
}
SqlCall rowConstructor = (SqlCall) operand;
if (conformance.isInsertSubsetColumnsAllowed() && targetRowType.isStruct() && rowConstructor.operandCount() < targetRowType.getFieldCount()) {
targetRowType = typeFactory.createStructType(targetRowType.getFieldList().subList(0, rowConstructor.operandCount()));
} else if (targetRowType.isStruct() && rowConstructor.operandCount() != targetRowType.getFieldCount()) {
return;
}
inferUnknownTypes(targetRowType, scope, rowConstructor);
if (targetRowType.isStruct()) {
for (Pair<SqlNode, RelDataTypeField> pair : Pair.zip(rowConstructor.getOperandList(), targetRowType.getFieldList())) {
if (!pair.right.getType().isNullable() && SqlUtil.isNullLiteral(pair.left, false)) {
throw newValidationError(node, RESOURCE.columnNotNullable(pair.right.getName()));
}
}
}
}
for (SqlNode operand : operands) {
operand.validate(this, scope);
}
// validate that all row types have the same number of columns
// and that expressions in each column are compatible.
// A values expression is turned into something that looks like
// ROW(type00, type01,...), ROW(type11,...),...
final int rowCount = operands.size();
if (rowCount >= 2) {
SqlCall firstRow = (SqlCall) operands.get(0);
final int columnCount = firstRow.operandCount();
// 1. check that all rows have the same cols length
for (SqlNode operand : operands) {
SqlCall thisRow = (SqlCall) operand;
if (columnCount != thisRow.operandCount()) {
throw newValidationError(node, RESOURCE.incompatibleValueType(SqlStdOperatorTable.VALUES.getName()));
}
}
// 2. check if types at i:th position in each row are compatible
for (int col = 0; col < columnCount; col++) {
final int c = col;
final RelDataType type = typeFactory.leastRestrictive(new AbstractList<RelDataType>() {
public RelDataType get(int row) {
SqlCall thisRow = (SqlCall) operands.get(row);
return deriveType(scope, thisRow.operand(c));
}
public int size() {
return rowCount;
}
});
if (null == type) {
throw newValidationError(node, RESOURCE.incompatibleValueType(SqlStdOperatorTable.VALUES.getName()));
}
}
}
}
use of org.apache.calcite.sql.SqlCall in project calcite by apache.
the class SqlValidatorImpl method registerSubQueries.
private void registerSubQueries(SqlValidatorScope parentScope, SqlNode node) {
if (node == null) {
return;
}
if (node.getKind().belongsTo(SqlKind.QUERY) || node.getKind() == SqlKind.MULTISET_QUERY_CONSTRUCTOR || node.getKind() == SqlKind.MULTISET_VALUE_CONSTRUCTOR) {
registerQuery(parentScope, null, node, node, null, false);
} else if (node instanceof SqlCall) {
validateNodeFeature(node);
SqlCall call = (SqlCall) node;
for (int i = 0; i < call.operandCount(); i++) {
registerOperandSubQueries(parentScope, call, i);
}
} else if (node instanceof SqlNodeList) {
SqlNodeList list = (SqlNodeList) node;
for (int i = 0, count = list.size(); i < count; i++) {
SqlNode listNode = list.get(i);
if (listNode.getKind().belongsTo(SqlKind.QUERY)) {
listNode = SqlStdOperatorTable.SCALAR_QUERY.createCall(listNode.getParserPosition(), listNode);
list.set(i, listNode);
}
registerSubQueries(parentScope, listNode);
}
} else {
// atomic node -- can be ignored
}
}
use of org.apache.calcite.sql.SqlCall 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.SqlCall in project calcite by apache.
the class SqlValidatorImpl method findTableColumnPair.
private Pair<String, String> findTableColumnPair(SqlIdentifier identifier, SqlValidatorScope scope) {
SqlCall call = SqlUtil.makeCall(getOperatorTable(), identifier);
if (call != null) {
return null;
}
SqlQualified qualified = scope.fullyQualify(identifier);
List<String> names = qualified.identifier.names;
if (names.size() < 2) {
return null;
}
return new Pair<>(names.get(names.size() - 2), Util.last(names));
}
use of org.apache.calcite.sql.SqlCall in project calcite by apache.
the class SqlValidatorImpl method validateExpr.
/**
* Validates an expression.
*
* @param expr Expression
* @param scope Scope in which expression occurs
*/
private void validateExpr(SqlNode expr, SqlValidatorScope scope) {
if (expr instanceof SqlCall) {
final SqlOperator op = ((SqlCall) expr).getOperator();
if (op.isAggregator() && op.requiresOver()) {
throw newValidationError(expr, RESOURCE.absentOverClause());
}
}
// Call on the expression to validate itself.
expr.validateExpr(this, scope);
// Perform any validation specific to the scope. For example, an
// aggregating scope requires that expressions are valid aggregations.
scope.validateExpr(expr);
}
Aggregations