use of org.apache.calcite.sql.SqlIdentifier in project flink by apache.
the class SqlValidatorImpl method validateMatchRecognize.
@Override
public void validateMatchRecognize(SqlCall call) {
final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
final MatchRecognizeScope scope = (MatchRecognizeScope) getMatchRecognizeScope(matchRecognize);
final MatchRecognizeNamespace ns = getNamespace(call).unwrap(MatchRecognizeNamespace.class);
assert ns.rowType == null;
// rows per match
final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
final boolean allRows = rowsPerMatch != null && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
final RelDataTypeFactory.Builder typeBuilder = typeFactory.builder();
// parse PARTITION BY column
SqlNodeList partitionBy = matchRecognize.getPartitionList();
if (partitionBy != null) {
for (SqlNode node : partitionBy) {
SqlIdentifier identifier = (SqlIdentifier) node;
identifier.validate(this, scope);
RelDataType type = deriveType(scope, identifier);
String name = identifier.names.get(1);
typeBuilder.add(name, type);
}
}
// parse ORDER BY column
SqlNodeList orderBy = matchRecognize.getOrderList();
if (orderBy != null) {
for (SqlNode node : orderBy) {
node.validate(this, scope);
SqlIdentifier identifier;
if (node instanceof SqlBasicCall) {
identifier = (SqlIdentifier) ((SqlBasicCall) node).getOperands()[0];
} else {
identifier = (SqlIdentifier) node;
}
if (allRows) {
RelDataType type = deriveType(scope, identifier);
String name = identifier.names.get(1);
if (!typeBuilder.nameExists(name)) {
typeBuilder.add(name, type);
}
}
}
}
if (allRows) {
final SqlValidatorNamespace sqlNs = getNamespace(matchRecognize.getTableRef());
final RelDataType inputDataType = sqlNs.getRowType();
for (RelDataTypeField fs : inputDataType.getFieldList()) {
if (!typeBuilder.nameExists(fs.getName())) {
typeBuilder.add(fs);
}
}
}
// retrieve pattern variables used in pattern and subset
SqlNode pattern = matchRecognize.getPattern();
PatternVarVisitor visitor = new PatternVarVisitor(scope);
pattern.accept(visitor);
SqlLiteral interval = matchRecognize.getInterval();
if (interval != null) {
interval.validate(this, scope);
if (((SqlIntervalLiteral) interval).signum() < 0) {
throw newValidationError(interval, RESOURCE.intervalMustBeNonNegative(interval.toValue()));
}
if (orderBy == null || orderBy.size() == 0) {
throw newValidationError(interval, RESOURCE.cannotUseWithinWithoutOrderBy());
}
SqlNode firstOrderByColumn = orderBy.getList().get(0);
SqlIdentifier identifier;
if (firstOrderByColumn instanceof SqlBasicCall) {
identifier = (SqlIdentifier) ((SqlBasicCall) firstOrderByColumn).getOperands()[0];
} else {
identifier = (SqlIdentifier) firstOrderByColumn;
}
RelDataType firstOrderByColumnType = deriveType(scope, identifier);
if (!(firstOrderByColumnType.getSqlTypeName() == SqlTypeName.TIMESTAMP || firstOrderByColumnType.getSqlTypeName() == SqlTypeName.TIMESTAMP_WITH_LOCAL_TIME_ZONE)) {
throw newValidationError(interval, RESOURCE.firstColumnOfOrderByMustBeTimestamp());
}
SqlNode expand = expand(interval, scope);
RelDataType type = deriveType(scope, expand);
setValidatedNodeType(interval, type);
}
validateDefinitions(matchRecognize, scope);
SqlNodeList subsets = matchRecognize.getSubsetList();
if (subsets != null && subsets.size() > 0) {
for (SqlNode node : subsets) {
List<SqlNode> operands = ((SqlCall) node).getOperandList();
String leftString = ((SqlIdentifier) operands.get(0)).getSimple();
if (scope.getPatternVars().contains(leftString)) {
throw newValidationError(operands.get(0), RESOURCE.patternVarAlreadyDefined(leftString));
}
scope.addPatternVar(leftString);
for (SqlNode right : (SqlNodeList) operands.get(1)) {
SqlIdentifier id = (SqlIdentifier) right;
if (!scope.getPatternVars().contains(id.getSimple())) {
throw newValidationError(id, RESOURCE.unknownPattern(id.getSimple()));
}
scope.addPatternVar(id.getSimple());
}
}
}
// validate AFTER ... SKIP TO
final SqlNode skipTo = matchRecognize.getAfter();
if (skipTo instanceof SqlCall) {
final SqlCall skipToCall = (SqlCall) skipTo;
final SqlIdentifier id = skipToCall.operand(0);
if (!scope.getPatternVars().contains(id.getSimple())) {
throw newValidationError(id, RESOURCE.unknownPattern(id.getSimple()));
}
}
List<Map.Entry<String, RelDataType>> measureColumns = validateMeasure(matchRecognize, scope, allRows);
for (Map.Entry<String, RelDataType> c : measureColumns) {
if (!typeBuilder.nameExists(c.getKey())) {
typeBuilder.add(c.getKey(), c.getValue());
}
}
final RelDataType rowType = typeBuilder.build();
if (matchRecognize.getMeasureList().size() == 0) {
ns.setType(getNamespace(matchRecognize.getTableRef()).getRowType());
} else {
ns.setType(rowType);
}
}
use of org.apache.calcite.sql.SqlIdentifier in project flink by apache.
the class SqlValidatorImpl method expandStar.
private boolean expandStar(List<SqlNode> selectItems, Set<String> aliases, List<Map.Entry<String, RelDataType>> fields, boolean includeSystemVars, SelectScope scope, SqlNode node) {
if (!(node instanceof SqlIdentifier)) {
return false;
}
final SqlIdentifier identifier = (SqlIdentifier) node;
if (!identifier.isStar()) {
return false;
}
final SqlParserPos startPosition = identifier.getParserPosition();
switch(identifier.names.size()) {
case 1:
boolean hasDynamicStruct = false;
for (ScopeChild child : scope.children) {
final int before = fields.size();
if (child.namespace.getRowType().isDynamicStruct()) {
hasDynamicStruct = true;
// don't expand star if the underneath table is dynamic.
// Treat this star as a special field in validation/conversion and
// wait until execution time to expand this star.
final SqlNode exp = new SqlIdentifier(ImmutableList.of(child.name, DynamicRecordType.DYNAMIC_STAR_PREFIX), startPosition);
addToSelectList(selectItems, aliases, fields, exp, scope, includeSystemVars);
} else {
final SqlNode from = child.namespace.getNode();
final SqlValidatorNamespace fromNs = getNamespace(from, scope);
assert fromNs != null;
final RelDataType rowType = fromNs.getRowType();
for (RelDataTypeField field : rowType.getFieldList()) {
String columnName = field.getName();
// TODO: do real implicit collation here
final SqlIdentifier exp = new SqlIdentifier(ImmutableList.of(child.name, columnName), startPosition);
// Don't add expanded rolled up columns
if (!isRolledUpColumn(exp, scope)) {
addOrExpandField(selectItems, aliases, fields, includeSystemVars, scope, exp, field);
}
}
}
if (child.nullable) {
for (int i = before; i < fields.size(); i++) {
final Map.Entry<String, RelDataType> entry = fields.get(i);
final RelDataType type = entry.getValue();
if (!type.isNullable()) {
fields.set(i, Pair.of(entry.getKey(), typeFactory.createTypeWithNullability(type, true)));
}
}
}
}
// the list, per standard SQL. Disabled if there are dynamic fields.
if (!hasDynamicStruct || Bug.CALCITE_2400_FIXED) {
new Permute(scope.getNode().getFrom(), 0).permute(selectItems, fields);
}
return true;
default:
final SqlIdentifier prefixId = identifier.skipLast(1);
final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl();
final SqlNameMatcher nameMatcher = scope.validator.catalogReader.nameMatcher();
scope.resolve(prefixId.names, nameMatcher, true, resolved);
if (resolved.count() == 0) {
// or "select r.* from e"
throw newValidationError(prefixId, RESOURCE.unknownIdentifier(prefixId.toString()));
}
final RelDataType rowType = resolved.only().rowType();
if (rowType.isDynamicStruct()) {
// don't expand star if the underneath table is dynamic.
addToSelectList(selectItems, aliases, fields, prefixId.plus(DynamicRecordType.DYNAMIC_STAR_PREFIX, startPosition), scope, includeSystemVars);
} else if (rowType.isStruct()) {
for (RelDataTypeField field : rowType.getFieldList()) {
String columnName = field.getName();
// TODO: do real implicit collation here
addOrExpandField(selectItems, aliases, fields, includeSystemVars, scope, prefixId.plus(columnName, startPosition), field);
}
} else {
throw newValidationError(prefixId, RESOURCE.starRequiresRecordType());
}
return true;
}
}
use of org.apache.calcite.sql.SqlIdentifier in project flink by apache.
the class SqlValidatorImpl method deriveConstructorType.
public RelDataType deriveConstructorType(SqlValidatorScope scope, SqlCall call, SqlFunction unresolvedConstructor, SqlFunction resolvedConstructor, List<RelDataType> argTypes) {
SqlIdentifier sqlIdentifier = unresolvedConstructor.getSqlIdentifier();
assert sqlIdentifier != null;
RelDataType type = catalogReader.getNamedType(sqlIdentifier);
if (type == null) {
// TODO jvs 12-Feb-2005: proper type name formatting
throw newValidationError(sqlIdentifier, RESOURCE.unknownDatatypeName(sqlIdentifier.toString()));
}
if (resolvedConstructor == null) {
if (call.operandCount() > 0) {
// no user-defined constructor could be found
throw handleUnresolvedFunction(call, unresolvedConstructor, argTypes, null);
}
} else {
SqlCall testCall = resolvedConstructor.createCall(call.getParserPosition(), call.getOperandList());
RelDataType returnType = resolvedConstructor.validateOperands(this, scope, testCall);
assert type == returnType;
}
if (config.identifierExpansion()) {
if (resolvedConstructor != null) {
((SqlBasicCall) call).setOperator(resolvedConstructor);
} else {
// fake a fully-qualified call to the default constructor
((SqlBasicCall) call).setOperator(new SqlFunction(type.getSqlIdentifier(), ReturnTypes.explicit(type), null, null, null, SqlFunctionCategory.USER_DEFINED_CONSTRUCTOR));
}
}
return type;
}
use of org.apache.calcite.sql.SqlIdentifier in project flink by apache.
the class SqlValidatorImpl method validateMeasure.
private List<Map.Entry<String, RelDataType>> validateMeasure(SqlMatchRecognize mr, MatchRecognizeScope scope, boolean allRows) {
final List<String> aliases = new ArrayList<>();
final List<SqlNode> sqlNodes = new ArrayList<>();
final SqlNodeList measures = mr.getMeasureList();
final List<Map.Entry<String, RelDataType>> fields = new ArrayList<>();
for (SqlNode measure : measures) {
assert measure instanceof SqlCall;
final String alias = deriveAlias(measure, aliases.size());
aliases.add(alias);
SqlNode expand = expand(measure, scope);
expand = navigationInMeasure(expand, allRows);
setOriginal(expand, measure);
inferUnknownTypes(unknownType, scope, expand);
final RelDataType type = deriveType(scope, expand);
setValidatedNodeType(measure, type);
fields.add(Pair.of(alias, type));
sqlNodes.add(SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, expand, new SqlIdentifier(alias, SqlParserPos.ZERO)));
}
SqlNodeList list = new SqlNodeList(sqlNodes, measures.getParserPosition());
inferUnknownTypes(unknownType, scope, list);
for (SqlNode node : list) {
validateExpr(node, scope);
}
mr.setOperand(SqlMatchRecognize.OPERAND_MEASURES, list);
return fields;
}
use of org.apache.calcite.sql.SqlIdentifier in project flink by apache.
the class SqlValidatorImpl method validateSelect.
/**
* Validates a SELECT statement.
*
* @param select Select statement
* @param targetRowType Desired row type, must not be null, may be the data type 'unknown'.
*/
protected void validateSelect(SqlSelect select, RelDataType targetRowType) {
assert targetRowType != null;
// Namespace is either a select namespace or a wrapper around one.
final SelectNamespace ns = getNamespace(select).unwrap(SelectNamespace.class);
// account.
assert ns.rowType == null;
if (select.isDistinct()) {
validateFeature(RESOURCE.sQLFeature_E051_01(), select.getModifierNode(SqlSelectKeyword.DISTINCT).getParserPosition());
}
final SqlNodeList selectItems = select.getSelectList();
RelDataType fromType = unknownType;
if (selectItems.size() == 1) {
final SqlNode selectItem = selectItems.get(0);
if (selectItem instanceof SqlIdentifier) {
SqlIdentifier id = (SqlIdentifier) selectItem;
if (id.isStar() && (id.names.size() == 1)) {
// Special case: for INSERT ... VALUES(?,?), the SQL
// standard says we're supposed to propagate the target
// types down. So iff the select list is an unqualified
// star (as it will be after an INSERT ... VALUES has been
// expanded), then propagate.
fromType = targetRowType;
}
}
}
// Make sure that items in FROM clause have distinct aliases.
final SelectScope fromScope = (SelectScope) getFromScope(select);
List<String> names = fromScope.getChildNames();
if (!catalogReader.nameMatcher().isCaseSensitive()) {
names = names.stream().map(s -> s.toUpperCase(Locale.ROOT)).collect(Collectors.toList());
}
final int duplicateAliasOrdinal = Util.firstDuplicate(names);
if (duplicateAliasOrdinal >= 0) {
final ScopeChild child = fromScope.children.get(duplicateAliasOrdinal);
throw newValidationError(child.namespace.getEnclosingNode(), RESOURCE.fromAliasDuplicate(child.name));
}
if (select.getFrom() == null) {
if (this.config.sqlConformance().isFromRequired()) {
throw newValidationError(select, RESOURCE.selectMissingFrom());
}
} else {
validateFrom(select.getFrom(), fromType, fromScope);
}
validateWhereClause(select);
validateGroupClause(select);
validateHavingClause(select);
validateWindowClause(select);
handleOffsetFetch(select.getOffset(), select.getFetch());
// Validate the SELECT clause late, because a select item might
// depend on the GROUP BY list, or the window function might reference
// window name in the WINDOW clause etc.
final RelDataType rowType = validateSelectList(selectItems, select, targetRowType);
ns.setType(rowType);
// Validate ORDER BY after we have set ns.rowType because in some
// dialects you can refer to columns of the select list, e.g.
// "SELECT empno AS x FROM emp ORDER BY x"
validateOrderList(select);
if (shouldCheckForRollUp(select.getFrom())) {
checkRollUpInSelectList(select);
checkRollUp(null, select, select.getWhere(), getWhereScope(select));
checkRollUp(null, select, select.getHaving(), getHavingScope(select));
checkRollUpInWindowDecl(select);
checkRollUpInGroupBy(select);
checkRollUpInOrderBy(select);
}
}
Aggregations