use of org.apache.calcite.sql.SqlBasicCall 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.
*
* <p>Returns null if and only if the original expression is null.
*
* @param node expression to be rewritten
* @param underFrom whether node appears directly under a FROM clause
* @return rewritten expression, or null if the original expression is null
*/
@PolyNull
protected SqlNode performUnconditionalRewrites(@PolyNull SqlNode node, boolean underFrom) {
if (node == null) {
return null;
}
// 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;
}
SqlNode 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) {
final SqlNodeList list = (SqlNodeList) node;
for (int i = 0; i < list.size(); i++) {
SqlNode operand = list.get(i);
SqlNode newOperand = performUnconditionalRewrites(operand, false);
if (newOperand != null) {
list.set(i, newOperand);
}
}
}
// now transform node itself
final SqlKind kind = node.getKind();
switch(kind) {
case VALUES:
// expression grow indefinitely.
return node;
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;
SqlSelect innerSelect = getInnerSelect(node);
if (innerSelect != null && isAggregate(innerSelect)) {
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 = SqlNonNullableAccessors.getSelectList(innerSelect);
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;
}
default:
break;
}
return node;
}
use of org.apache.calcite.sql.SqlBasicCall in project calcite by apache.
the class StandardConvertletTable method convertSubstring.
/**
* Converts a SUBSTRING expression.
*
* <p>Called automatically via reflection.
*/
public RexNode convertSubstring(SqlRexContext cx, SqlSubstringFunction op, SqlCall call) {
final SqlLibrary library = cx.getValidator().config().conformance().semantics();
final SqlBasicCall basicCall = (SqlBasicCall) call;
switch(library) {
case BIG_QUERY:
return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_BIG_QUERY);
case MYSQL:
return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_MYSQL);
case ORACLE:
return toRex(cx, basicCall, SqlLibraryOperators.SUBSTR_ORACLE);
case POSTGRESQL:
default:
return convertFunction(cx, op, call);
}
}
use of org.apache.calcite.sql.SqlBasicCall in project calcite by apache.
the class StandardConvertletTable method toRex.
private RexNode toRex(SqlRexContext cx, SqlBasicCall call, SqlFunction f) {
final SqlCall call2 = new SqlBasicCall(f, call.getOperandList(), call.getParserPosition());
final SqlRexConvertlet convertlet = requireNonNull(get(call2));
return convertlet.convertCall(cx, call2);
}
use of org.apache.calcite.sql.SqlBasicCall in project calcite by apache.
the class SqlToRelConverter method convertRowValues.
@Nullable
private RelNode convertRowValues(Blackboard bb, SqlNode rowList, Collection<SqlNode> rows, boolean allowLiteralsOnly, @Nullable RelDataType targetRowType) {
// NOTE jvs 30-Apr-2006: We combine all rows consisting entirely of
// literals into a single LogicalValues; this gives the optimizer a smaller
// input tree. For everything else (computed expressions, row
// sub-queries), we union each row in as a projection on top of a
// LogicalOneRow.
final ImmutableList.Builder<ImmutableList<RexLiteral>> tupleList = ImmutableList.builder();
final RelDataType listType = validator().getValidatedNodeType(rowList);
final RelDataType rowType;
if (targetRowType != null) {
rowType = typeFactory.createTypeWithNullability(targetRowType, SqlTypeUtil.containsNullable(listType));
} else {
rowType = SqlTypeUtil.promoteToRowType(typeFactory, listType, null);
}
final List<RelNode> unionInputs = new ArrayList<>();
for (SqlNode node : rows) {
SqlBasicCall call;
if (isRowConstructor(node)) {
call = (SqlBasicCall) node;
ImmutableList.Builder<RexLiteral> tuple = ImmutableList.builder();
for (Ord<SqlNode> operand : Ord.zip(call.getOperandList())) {
RexLiteral rexLiteral = convertLiteralInValuesList(operand.e, bb, rowType, operand.i);
if ((rexLiteral == null) && allowLiteralsOnly) {
return null;
}
if ((rexLiteral == null) || !config.isCreateValuesRel()) {
// fallback to convertRowConstructor
tuple = null;
break;
}
tuple.add(rexLiteral);
}
if (tuple != null) {
tupleList.add(tuple.build());
continue;
}
} else {
RexLiteral rexLiteral = convertLiteralInValuesList(node, bb, rowType, 0);
if ((rexLiteral != null) && config.isCreateValuesRel()) {
tupleList.add(ImmutableList.of(rexLiteral));
continue;
} else {
if ((rexLiteral == null) && allowLiteralsOnly) {
return null;
}
}
// convert "1" to "row(1)"
call = (SqlBasicCall) SqlStdOperatorTable.ROW.createCall(SqlParserPos.ZERO, node);
}
unionInputs.add(convertRowConstructor(bb, call));
}
LogicalValues values = LogicalValues.create(cluster, rowType, tupleList.build());
RelNode resultRel;
if (unionInputs.isEmpty()) {
resultRel = values;
} else {
if (!values.getTuples().isEmpty()) {
unionInputs.add(values);
}
resultRel = LogicalUnion.create(unionInputs, true);
}
leaves.put(resultRel, resultRel.getRowType().getFieldCount());
return resultRel;
}
use of org.apache.calcite.sql.SqlBasicCall in project calcite by apache.
the class SqlToRelConverter method convertNonCorrelatedSubQuery.
/**
* Determines if a sub-query is non-correlated and if so, converts it to a
* constant.
*
* @param subQuery the call that references the sub-query
* @param bb blackboard used to convert the sub-query
* @param converted RelNode tree corresponding to the sub-query
* @param isExists true if the sub-query is part of an EXISTS expression
* @return Whether the sub-query can be converted to a constant
*/
private boolean convertNonCorrelatedSubQuery(SubQuery subQuery, Blackboard bb, RelNode converted, boolean isExists) {
SqlCall call = (SqlBasicCall) subQuery.node;
if (subQueryConverter.canConvertSubQuery() && isSubQueryNonCorrelated(converted, bb)) {
// First check if the sub-query has already been converted
// because it's a nested sub-query. If so, don't re-evaluate
// it again.
RexNode constExpr = mapConvertedNonCorrSubqs.get(call);
if (constExpr == null) {
constExpr = subQueryConverter.convertSubQuery(call, this, isExists, config.isExplain());
}
if (constExpr != null) {
subQuery.expr = constExpr;
mapConvertedNonCorrSubqs.put(call, constExpr);
return true;
}
}
return false;
}
Aggregations