use of org.apache.calcite.sql.SqlNodeList 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.SqlNodeList in project calcite by apache.
the class RelToSqlConverter method visit.
/**
* @see #dispatch
*/
public Result visit(Values e) {
final List<Clause> clauses = ImmutableList.of(Clause.SELECT);
final Map<String, RelDataType> pairs = ImmutableMap.of();
final Context context = aliasContext(pairs, false);
SqlNode query;
final boolean rename = stack.size() <= 1 || !(Iterables.get(stack, 1).r instanceof TableModify);
final List<String> fieldNames = e.getRowType().getFieldNames();
if (!dialect.supportsAliasedValues() && rename) {
// Oracle does not support "AS t (c1, c2)". So instead of
// (VALUES (v0, v1), (v2, v3)) AS t (c0, c1)
// we generate
// SELECT v0 AS c0, v1 AS c1 FROM DUAL
// UNION ALL
// SELECT v2 AS c0, v3 AS c1 FROM DUAL
List<SqlSelect> list = new ArrayList<>();
for (List<RexLiteral> tuple : e.getTuples()) {
final List<SqlNode> values2 = new ArrayList<>();
final SqlNodeList exprList = exprList(context, tuple);
for (Pair<SqlNode, String> value : Pair.zip(exprList, fieldNames)) {
values2.add(SqlStdOperatorTable.AS.createCall(POS, value.left, new SqlIdentifier(value.right, POS)));
}
list.add(new SqlSelect(POS, null, new SqlNodeList(values2, POS), new SqlIdentifier("DUAL", POS), null, null, null, null, null, null, null));
}
if (list.size() == 1) {
query = list.get(0);
} else {
query = SqlStdOperatorTable.UNION_ALL.createCall(new SqlNodeList(list, POS));
}
} else {
// Generate ANSI syntax
// (VALUES (v0, v1), (v2, v3))
// or, if rename is required
// (VALUES (v0, v1), (v2, v3)) AS t (c0, c1)
final SqlNodeList selects = new SqlNodeList(POS);
for (List<RexLiteral> tuple : e.getTuples()) {
selects.add(ANONYMOUS_ROW.createCall(exprList(context, tuple)));
}
query = SqlStdOperatorTable.VALUES.createCall(selects);
if (rename) {
final List<SqlNode> list = new ArrayList<>();
list.add(query);
list.add(new SqlIdentifier("t", POS));
for (String fieldName : fieldNames) {
list.add(new SqlIdentifier(fieldName, POS));
}
query = SqlStdOperatorTable.AS.createCall(POS, list);
}
}
return result(query, clauses, e, null);
}
use of org.apache.calcite.sql.SqlNodeList in project calcite by apache.
the class RelToSqlConverter method visit.
/**
* @see #dispatch
*/
public Result visit(Match e) {
final RelNode input = e.getInput();
final Result x = visitChild(0, input);
final Context context = matchRecognizeContext(x.qualifiedContext());
SqlNode tableRef = x.asQueryOrValues();
final List<SqlNode> partitionSqlList = new ArrayList<>();
if (e.getPartitionKeys() != null) {
for (RexNode rex : e.getPartitionKeys()) {
SqlNode sqlNode = context.toSql(null, rex);
partitionSqlList.add(sqlNode);
}
}
final SqlNodeList partitionList = new SqlNodeList(partitionSqlList, POS);
final List<SqlNode> orderBySqlList = new ArrayList<>();
if (e.getOrderKeys() != null) {
for (RelFieldCollation fc : e.getOrderKeys().getFieldCollations()) {
if (fc.nullDirection != RelFieldCollation.NullDirection.UNSPECIFIED) {
boolean first = fc.nullDirection == RelFieldCollation.NullDirection.FIRST;
SqlNode nullDirectionNode = dialect.emulateNullDirection(context.field(fc.getFieldIndex()), first, fc.direction.isDescending());
if (nullDirectionNode != null) {
orderBySqlList.add(nullDirectionNode);
fc = new RelFieldCollation(fc.getFieldIndex(), fc.getDirection(), RelFieldCollation.NullDirection.UNSPECIFIED);
}
}
orderBySqlList.add(context.toSql(fc));
}
}
final SqlNodeList orderByList = new SqlNodeList(orderBySqlList, SqlParserPos.ZERO);
final SqlLiteral rowsPerMatch = e.isAllRows() ? SqlMatchRecognize.RowsPerMatchOption.ALL_ROWS.symbol(POS) : SqlMatchRecognize.RowsPerMatchOption.ONE_ROW.symbol(POS);
final SqlNode after;
if (e.getAfter() instanceof RexLiteral) {
SqlMatchRecognize.AfterOption value = (SqlMatchRecognize.AfterOption) ((RexLiteral) e.getAfter()).getValue2();
after = SqlLiteral.createSymbol(value, POS);
} else {
RexCall call = (RexCall) e.getAfter();
String operand = RexLiteral.stringValue(call.getOperands().get(0));
after = call.getOperator().createCall(POS, new SqlIdentifier(operand, POS));
}
RexNode rexPattern = e.getPattern();
final SqlNode pattern = context.toSql(null, rexPattern);
final SqlLiteral strictStart = SqlLiteral.createBoolean(e.isStrictStart(), POS);
final SqlLiteral strictEnd = SqlLiteral.createBoolean(e.isStrictEnd(), POS);
RexLiteral rexInterval = (RexLiteral) e.getInterval();
SqlIntervalLiteral interval = null;
if (rexInterval != null) {
interval = (SqlIntervalLiteral) context.toSql(null, rexInterval);
}
final SqlNodeList subsetList = new SqlNodeList(POS);
for (Map.Entry<String, SortedSet<String>> entry : e.getSubsets().entrySet()) {
SqlNode left = new SqlIdentifier(entry.getKey(), POS);
List<SqlNode> rhl = Lists.newArrayList();
for (String right : entry.getValue()) {
rhl.add(new SqlIdentifier(right, POS));
}
subsetList.add(SqlStdOperatorTable.EQUALS.createCall(POS, left, new SqlNodeList(rhl, POS)));
}
final SqlNodeList measureList = new SqlNodeList(POS);
for (Map.Entry<String, RexNode> entry : e.getMeasures().entrySet()) {
final String alias = entry.getKey();
final SqlNode sqlNode = context.toSql(null, entry.getValue());
measureList.add(as(sqlNode, alias));
}
final SqlNodeList patternDefList = new SqlNodeList(POS);
for (Map.Entry<String, RexNode> entry : e.getPatternDefinitions().entrySet()) {
final String alias = entry.getKey();
final SqlNode sqlNode = context.toSql(null, entry.getValue());
patternDefList.add(as(sqlNode, alias));
}
final SqlNode matchRecognize = new SqlMatchRecognize(POS, tableRef, pattern, strictStart, strictEnd, patternDefList, measureList, after, subsetList, rowsPerMatch, partitionList, orderByList, interval);
return result(matchRecognize, Expressions.list(Clause.FROM), e, null);
}
use of org.apache.calcite.sql.SqlNodeList 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.SqlNodeList in project calcite by apache.
the class SqlValidatorImpl method validateDefinitions.
private void validateDefinitions(SqlMatchRecognize mr, MatchRecognizeScope scope) {
final Set<String> aliases = catalogReader.nameMatcher().isCaseSensitive() ? new LinkedHashSet<String>() : new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
for (SqlNode item : mr.getPatternDefList().getList()) {
final String alias = alias(item);
if (!aliases.add(alias)) {
throw newValidationError(item, Static.RESOURCE.patternVarAlreadyDefined(alias));
}
scope.addPatternVar(alias);
}
final List<SqlNode> sqlNodes = new ArrayList<>();
for (SqlNode item : mr.getPatternDefList().getList()) {
final String alias = alias(item);
SqlNode expand = expand(item, scope);
expand = navigationInDefine(expand, alias);
setOriginal(expand, item);
inferUnknownTypes(booleanType, scope, expand);
expand.validate(this, scope);
// Some extra work need required here.
// In PREV, NEXT, FINAL and LAST, only one pattern variable is allowed.
sqlNodes.add(SqlStdOperatorTable.AS.createCall(SqlParserPos.ZERO, expand, new SqlIdentifier(alias, SqlParserPos.ZERO)));
final RelDataType type = deriveType(scope, expand);
if (!SqlTypeUtil.inBooleanFamily(type)) {
throw newValidationError(expand, RESOURCE.condMustBeBoolean("DEFINE"));
}
setValidatedNodeType(item, type);
}
SqlNodeList list = new SqlNodeList(sqlNodes, mr.getPatternDefList().getParserPosition());
inferUnknownTypes(unknownType, scope, list);
for (SqlNode node : list) {
validateExpr(node, scope);
}
mr.setOperand(SqlMatchRecognize.OPERAND_PATTERN_DEFINES, list);
}
Aggregations