use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlSubstringFunction method checkOperandTypes.
public boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
SqlValidator validator = callBinding.getValidator();
SqlValidatorScope scope = callBinding.getScope();
final List<SqlNode> operands = callBinding.operands();
int n = operands.size();
assert (3 == n) || (2 == n);
if (!OperandTypes.STRING.checkSingleOperandType(callBinding, operands.get(0), 0, throwOnFailure)) {
return false;
}
if (2 == n) {
if (!OperandTypes.NUMERIC.checkSingleOperandType(callBinding, operands.get(1), 0, throwOnFailure)) {
return false;
}
} else {
RelDataType t1 = validator.deriveType(scope, operands.get(1));
RelDataType t2 = validator.deriveType(scope, operands.get(2));
if (SqlTypeUtil.inCharFamily(t1)) {
if (!OperandTypes.STRING.checkSingleOperandType(callBinding, operands.get(1), 0, throwOnFailure)) {
return false;
}
if (!OperandTypes.STRING.checkSingleOperandType(callBinding, operands.get(2), 0, throwOnFailure)) {
return false;
}
if (!SqlTypeUtil.isCharTypeComparable(callBinding, operands, throwOnFailure)) {
return false;
}
} else {
if (!OperandTypes.NUMERIC.checkSingleOperandType(callBinding, operands.get(1), 0, throwOnFailure)) {
return false;
}
if (!OperandTypes.NUMERIC.checkSingleOperandType(callBinding, operands.get(2), 0, throwOnFailure)) {
return false;
}
}
if (!SqlTypeUtil.inSameFamily(t1, t2)) {
if (throwOnFailure) {
throw callBinding.newValidationSignatureError();
}
return false;
}
}
return true;
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlOperatorBaseTest method testArgumentBounds.
/**
* Test that calls all operators with all possible argument types, and for
* each type, with a set of tricky values.
*/
@Test
public void testArgumentBounds() {
if (!CalciteAssert.ENABLE_SLOW) {
return;
}
final SqlValidatorImpl validator = (SqlValidatorImpl) tester.getValidator();
final SqlValidatorScope scope = validator.getEmptyScope();
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
final Builder builder = new Builder(typeFactory);
builder.add0(SqlTypeName.BOOLEAN, true, false);
builder.add0(SqlTypeName.TINYINT, 0, 1, -3, Byte.MAX_VALUE, Byte.MIN_VALUE);
builder.add0(SqlTypeName.SMALLINT, 0, 1, -4, Short.MAX_VALUE, Short.MIN_VALUE);
builder.add0(SqlTypeName.INTEGER, 0, 1, -2, Integer.MIN_VALUE, Integer.MAX_VALUE);
builder.add0(SqlTypeName.BIGINT, 0, 1, -5, Integer.MAX_VALUE, Long.MAX_VALUE, Long.MIN_VALUE);
builder.add1(SqlTypeName.VARCHAR, 11, "", " ", "hello world");
builder.add1(SqlTypeName.CHAR, 5, "", "e", "hello");
builder.add0(SqlTypeName.TIMESTAMP, 0L, DateTimeUtils.MILLIS_PER_DAY);
for (SqlOperator op : SqlStdOperatorTable.instance().getOperatorList()) {
switch(op.getKind()) {
// can't handle the flag argument
case TRIM:
case EXISTS:
continue;
}
switch(op.getSyntax()) {
case SPECIAL:
continue;
}
final SqlOperandTypeChecker typeChecker = op.getOperandTypeChecker();
if (typeChecker == null) {
continue;
}
final SqlOperandCountRange range = typeChecker.getOperandCountRange();
for (int n = range.getMin(), max = range.getMax(); n <= max; n++) {
final List<List<ValueType>> argValues = Collections.nCopies(n, builder.values);
for (final List<ValueType> args : Linq4j.product(argValues)) {
SqlNodeList nodeList = new SqlNodeList(SqlParserPos.ZERO);
int nullCount = 0;
for (ValueType arg : args) {
if (arg.value == null) {
++nullCount;
}
nodeList.add(arg.node);
}
final SqlCall call = op.createCall(nodeList);
final SqlCallBinding binding = new SqlCallBinding(validator, scope, call);
if (!typeChecker.checkOperandTypes(binding, false)) {
continue;
}
final SqlPrettyWriter writer = new SqlPrettyWriter(CalciteSqlDialect.DEFAULT);
op.unparse(writer, call, 0, 0);
final String s = writer.toSqlString().toString();
if (s.startsWith("OVERLAY(") || s.contains(" / 0") || s.matches("MOD\\(.*, 0\\)")) {
continue;
}
final Strong.Policy policy = Strong.policy(op.kind);
try {
if (nullCount > 0 && policy == Strong.Policy.ANY) {
tester.checkNull(s);
} else {
final String query;
if (op instanceof SqlAggFunction) {
if (op.requiresOrder()) {
query = "SELECT " + s + " OVER () FROM (VALUES (1))";
} else {
query = "SELECT " + s + " FROM (VALUES (1))";
}
} else {
query = SqlTesterImpl.buildQuery(s);
}
tester.check(query, SqlTests.ANY_TYPE_CHECKER, SqlTests.ANY_PARAMETER_CHECKER, SqlTests.ANY_RESULT_CHECKER);
}
} catch (Error e) {
System.out.println(s + ": " + e.getMessage());
throw e;
} catch (Exception e) {
System.out.println("Failed: " + s + ": " + e.getMessage());
}
}
}
}
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method convertMatchRecognize.
protected void convertMatchRecognize(Blackboard bb, SqlCall call) {
final SqlMatchRecognize matchRecognize = (SqlMatchRecognize) call;
final SqlValidatorNamespace ns = validator.getNamespace(matchRecognize);
final SqlValidatorScope scope = validator.getMatchRecognizeScope(matchRecognize);
final Blackboard matchBb = createBlackboard(scope, null, false);
final RelDataType rowType = ns.getRowType();
// convert inner query, could be a table name or a derived table
SqlNode expr = matchRecognize.getTableRef();
convertFrom(matchBb, expr);
final RelNode input = matchBb.root;
// PARTITION BY
final SqlNodeList partitionList = matchRecognize.getPartitionList();
final List<RexNode> partitionKeys = new ArrayList<>();
for (SqlNode partition : partitionList) {
RexNode e = matchBb.convertExpression(partition);
partitionKeys.add(e);
}
// ORDER BY
final SqlNodeList orderList = matchRecognize.getOrderList();
final List<RelFieldCollation> orderKeys = new ArrayList<>();
for (SqlNode order : orderList) {
final RelFieldCollation.Direction direction;
switch(order.getKind()) {
case DESCENDING:
direction = RelFieldCollation.Direction.DESCENDING;
order = ((SqlCall) order).operand(0);
break;
case NULLS_FIRST:
case NULLS_LAST:
throw new AssertionError();
default:
direction = RelFieldCollation.Direction.ASCENDING;
break;
}
final RelFieldCollation.NullDirection nullDirection = validator.getDefaultNullCollation().last(desc(direction)) ? RelFieldCollation.NullDirection.LAST : RelFieldCollation.NullDirection.FIRST;
RexNode e = matchBb.convertExpression(order);
orderKeys.add(new RelFieldCollation(((RexInputRef) e).getIndex(), direction, nullDirection));
}
final RelCollation orders = cluster.traitSet().canonize(RelCollations.of(orderKeys));
// convert pattern
final Set<String> patternVarsSet = new HashSet<>();
SqlNode pattern = matchRecognize.getPattern();
final SqlBasicVisitor<RexNode> patternVarVisitor = new SqlBasicVisitor<RexNode>() {
@Override
public RexNode visit(SqlCall call) {
List<SqlNode> operands = call.getOperandList();
List<RexNode> newOperands = Lists.newArrayList();
for (SqlNode node : operands) {
newOperands.add(node.accept(this));
}
return rexBuilder.makeCall(validator.getUnknownType(), call.getOperator(), newOperands);
}
@Override
public RexNode visit(SqlIdentifier id) {
assert id.isSimple();
patternVarsSet.add(id.getSimple());
return rexBuilder.makeLiteral(id.getSimple());
}
@Override
public RexNode visit(SqlLiteral literal) {
if (literal instanceof SqlNumericLiteral) {
return rexBuilder.makeExactLiteral(BigDecimal.valueOf(literal.intValue(true)));
} else {
return rexBuilder.makeLiteral(literal.booleanValue());
}
}
};
final RexNode patternNode = pattern.accept(patternVarVisitor);
SqlLiteral interval = matchRecognize.getInterval();
RexNode intervalNode = null;
if (interval != null) {
intervalNode = matchBb.convertLiteral(interval);
}
// convert subset
final SqlNodeList subsets = matchRecognize.getSubsetList();
final Map<String, TreeSet<String>> subsetMap = Maps.newHashMap();
for (SqlNode node : subsets) {
List<SqlNode> operands = ((SqlCall) node).getOperandList();
SqlIdentifier left = (SqlIdentifier) operands.get(0);
patternVarsSet.add(left.getSimple());
SqlNodeList rights = (SqlNodeList) operands.get(1);
final TreeSet<String> list = new TreeSet<String>();
for (SqlNode right : rights) {
assert right instanceof SqlIdentifier;
list.add(((SqlIdentifier) right).getSimple());
}
subsetMap.put(left.getSimple(), list);
}
SqlNode afterMatch = matchRecognize.getAfter();
if (afterMatch == null) {
afterMatch = SqlMatchRecognize.AfterOption.SKIP_TO_NEXT_ROW.symbol(SqlParserPos.ZERO);
}
final RexNode after;
if (afterMatch instanceof SqlCall) {
List<SqlNode> operands = ((SqlCall) afterMatch).getOperandList();
SqlOperator operator = ((SqlCall) afterMatch).getOperator();
assert operands.size() == 1;
SqlIdentifier id = (SqlIdentifier) operands.get(0);
assert patternVarsSet.contains(id.getSimple()) : id.getSimple() + " not defined in pattern";
RexNode rex = rexBuilder.makeLiteral(id.getSimple());
after = rexBuilder.makeCall(validator.getUnknownType(), operator, ImmutableList.of(rex));
} else {
after = matchBb.convertExpression(afterMatch);
}
matchBb.setPatternVarRef(true);
// convert measures
final ImmutableMap.Builder<String, RexNode> measureNodes = ImmutableMap.builder();
for (SqlNode measure : matchRecognize.getMeasureList()) {
List<SqlNode> operands = ((SqlCall) measure).getOperandList();
String alias = ((SqlIdentifier) operands.get(1)).getSimple();
RexNode rex = matchBb.convertExpression(operands.get(0));
measureNodes.put(alias, rex);
}
// convert definitions
final ImmutableMap.Builder<String, RexNode> definitionNodes = ImmutableMap.builder();
for (SqlNode def : matchRecognize.getPatternDefList()) {
List<SqlNode> operands = ((SqlCall) def).getOperandList();
String alias = ((SqlIdentifier) operands.get(1)).getSimple();
RexNode rex = matchBb.convertExpression(operands.get(0));
definitionNodes.put(alias, rex);
}
final SqlLiteral rowsPerMatch = matchRecognize.getRowsPerMatch();
final boolean allRows = rowsPerMatch != null && rowsPerMatch.getValue() == SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS;
matchBb.setPatternVarRef(false);
final RelFactories.MatchFactory factory = RelFactories.DEFAULT_MATCH_FACTORY;
final RelNode rel = factory.createMatch(input, patternNode, rowType, matchRecognize.getStrictStart().booleanValue(), matchRecognize.getStrictEnd().booleanValue(), definitionNodes.build(), measureNodes.build(), after, subsetMap, allRows, partitionKeys, orders, intervalNode);
bb.setRoot(rel, false);
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlToRelConverter method convertSelect.
/**
* Converts a SELECT statement's parse tree into a relational expression.
*/
public RelNode convertSelect(SqlSelect select, boolean top) {
final SqlValidatorScope selectScope = validator.getWhereScope(select);
final Blackboard bb = createBlackboard(selectScope, null, top);
convertSelectImpl(bb, select);
return bb.root;
}
use of org.apache.calcite.sql.validate.SqlValidatorScope in project calcite by apache.
the class SqlWindow method validate.
@Override
public void validate(SqlValidator validator, SqlValidatorScope scope) {
// REVIEW
SqlValidatorScope operandScope = scope;
SqlIdentifier declName = this.declName;
SqlIdentifier refName = this.refName;
SqlNodeList partitionList = this.partitionList;
SqlNodeList orderList = this.orderList;
SqlLiteral isRows = this.isRows;
SqlNode lowerBound = this.lowerBound;
SqlNode upperBound = this.upperBound;
SqlLiteral allowPartial = this.allowPartial;
if (refName != null) {
SqlWindow win = validator.resolveWindow(this, operandScope, false);
partitionList = win.partitionList;
orderList = win.orderList;
isRows = win.isRows;
lowerBound = win.lowerBound;
upperBound = win.upperBound;
allowPartial = win.allowPartial;
}
for (SqlNode partitionItem : partitionList) {
try {
partitionItem.accept(Util.OverFinder.INSTANCE);
} catch (ControlFlowException e) {
throw validator.newValidationError(this, RESOURCE.partitionbyShouldNotContainOver());
}
partitionItem.validateExpr(validator, operandScope);
}
for (SqlNode orderItem : orderList) {
boolean savedColumnReferenceExpansion = validator.getColumnReferenceExpansion();
validator.setColumnReferenceExpansion(false);
try {
orderItem.accept(Util.OverFinder.INSTANCE);
} catch (ControlFlowException e) {
throw validator.newValidationError(this, RESOURCE.orderbyShouldNotContainOver());
}
try {
orderItem.validateExpr(validator, scope);
} finally {
validator.setColumnReferenceExpansion(savedColumnReferenceExpansion);
}
}
// 6.10 rule 6a Function RANK & DENSE_RANK require ORDER BY clause
if (orderList.size() == 0 && !SqlValidatorUtil.containsMonotonic(scope) && windowCall != null && windowCall.getOperator().requiresOrder()) {
throw validator.newValidationError(this, RESOURCE.funcNeedsOrderBy());
}
// Run framing checks if there are any
if (upperBound != null || lowerBound != null) {
// 6.10 Rule 6a RANK & DENSE_RANK do not allow ROWS or RANGE
if (windowCall != null && !windowCall.getOperator().allowsFraming()) {
throw validator.newValidationError(isRows, RESOURCE.rankWithFrame());
}
SqlTypeFamily orderTypeFam = null;
// SQL03 7.10 Rule 11a
if (orderList.size() > 0) {
// if order by is a compound list then range not allowed
if (orderList.size() > 1 && !isRows()) {
throw validator.newValidationError(isRows, RESOURCE.compoundOrderByProhibitsRange());
}
// get the type family for the sort key for Frame Boundary Val.
RelDataType orderType = validator.deriveType(operandScope, orderList.get(0));
orderTypeFam = orderType.getSqlTypeName().getFamily();
} else {
// sorted already
if (!isRows() && !SqlValidatorUtil.containsMonotonic(scope)) {
throw validator.newValidationError(this, RESOURCE.overMissingOrderBy());
}
}
// Let the bounds validate themselves
validateFrameBoundary(lowerBound, isRows(), orderTypeFam, validator, operandScope);
validateFrameBoundary(upperBound, isRows(), orderTypeFam, validator, operandScope);
// Validate across boundaries. 7.10 Rule 8 a-d
checkSpecialLiterals(this, validator);
} else if (orderList.size() == 0 && !SqlValidatorUtil.containsMonotonic(scope) && windowCall != null && windowCall.getOperator().requiresOrder()) {
throw validator.newValidationError(this, RESOURCE.overMissingOrderBy());
}
if (!isRows() && !isAllowPartial()) {
throw validator.newValidationError(allowPartial, RESOURCE.cannotUseDisallowPartialWithRange());
}
}
Aggregations