use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlNode in project calcite by apache.
the class SqlToRelConverter method substituteSubQuery.
private void substituteSubQuery(Blackboard bb, SubQuery subQuery) {
final RexNode expr = subQuery.expr;
if (expr != null) {
// Already done.
return;
}
final SqlBasicCall call;
final RelNode rel;
final SqlNode query;
final RelOptUtil.Exists converted;
switch(subQuery.node.getKind()) {
case CURSOR:
convertCursor(bb, subQuery);
return;
case MULTISET_QUERY_CONSTRUCTOR:
case MULTISET_VALUE_CONSTRUCTOR:
case ARRAY_QUERY_CONSTRUCTOR:
rel = convertMultisets(ImmutableList.of(subQuery.node), bb);
subQuery.expr = bb.register(rel, JoinRelType.INNER);
return;
case IN:
case NOT_IN:
case SOME:
case ALL:
call = (SqlBasicCall) subQuery.node;
query = call.operand(1);
if (!config.isExpand() && !(query instanceof SqlNodeList)) {
return;
}
final SqlNode leftKeyNode = call.operand(0);
final List<RexNode> leftKeys;
switch(leftKeyNode.getKind()) {
case ROW:
leftKeys = Lists.newArrayList();
for (SqlNode sqlExpr : ((SqlBasicCall) leftKeyNode).getOperandList()) {
leftKeys.add(bb.convertExpression(sqlExpr));
}
break;
default:
leftKeys = ImmutableList.of(bb.convertExpression(leftKeyNode));
}
if (query instanceof SqlNodeList) {
SqlNodeList valueList = (SqlNodeList) query;
if (!containsNullLiteral(valueList) && valueList.size() < config.getInSubQueryThreshold()) {
// We're under the threshold, so convert to OR.
subQuery.expr = convertInToOr(bb, leftKeys, valueList, (SqlInOperator) call.getOperator());
return;
}
// Otherwise, let convertExists translate
// values list into an inline table for the
// reference to Q below.
}
// Project out the search columns from the left side
// Q1:
// "select from emp where emp.deptno in (select col1 from T)"
//
// is converted to
//
// "select from
// emp inner join (select distinct col1 from T)) q
// on emp.deptno = q.col1
//
// Q2:
// "select from emp where emp.deptno not in (Q)"
//
// is converted to
//
// "select from
// emp left outer join (select distinct col1, TRUE from T) q
// on emp.deptno = q.col1
// where emp.deptno <> null
// and q.indicator <> TRUE"
//
final RelDataType targetRowType = SqlTypeUtil.promoteToRowType(typeFactory, validator.getValidatedNodeType(leftKeyNode), null);
final boolean notIn = call.getOperator().kind == SqlKind.NOT_IN;
converted = convertExists(query, RelOptUtil.SubQueryType.IN, subQuery.logic, notIn, targetRowType);
if (converted.indicator) {
// Generate
// emp CROSS JOIN (SELECT COUNT(*) AS c,
// COUNT(deptno) AS ck FROM dept)
final RelDataType longType = typeFactory.createSqlType(SqlTypeName.BIGINT);
// fragile
final RelNode seek = converted.r.getInput(0);
final int keyCount = leftKeys.size();
final List<Integer> args = ImmutableIntList.range(0, keyCount);
LogicalAggregate aggregate = LogicalAggregate.create(seek, ImmutableBitSet.of(), null, ImmutableList.of(AggregateCall.create(SqlStdOperatorTable.COUNT, false, false, ImmutableList.<Integer>of(), -1, longType, null), AggregateCall.create(SqlStdOperatorTable.COUNT, false, false, args, -1, longType, null)));
LogicalJoin join = LogicalJoin.create(bb.root, aggregate, rexBuilder.makeLiteral(true), ImmutableSet.<CorrelationId>of(), JoinRelType.INNER);
bb.setRoot(join, false);
}
final RexNode rex = bb.register(converted.r, converted.outerJoin ? JoinRelType.LEFT : JoinRelType.INNER, leftKeys);
RelOptUtil.Logic logic = subQuery.logic;
switch(logic) {
case TRUE_FALSE_UNKNOWN:
case UNKNOWN_AS_TRUE:
if (!converted.indicator) {
logic = RelOptUtil.Logic.TRUE_FALSE;
}
}
subQuery.expr = translateIn(logic, bb.root, rex);
if (notIn) {
subQuery.expr = rexBuilder.makeCall(SqlStdOperatorTable.NOT, subQuery.expr);
}
return;
case EXISTS:
// "select from emp where exists (select a from T)"
//
// is converted to the following if the sub-query is correlated:
//
// "select from emp left outer join (select AGG_TRUE() as indicator
// from T group by corr_var) q where q.indicator is true"
//
// If there is no correlation, the expression is replaced with a
// boolean indicating whether the sub-query returned 0 or >= 1 row.
call = (SqlBasicCall) subQuery.node;
query = call.operand(0);
if (!config.isExpand()) {
return;
}
converted = convertExists(query, RelOptUtil.SubQueryType.EXISTS, subQuery.logic, true, null);
assert !converted.indicator;
if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, true)) {
return;
}
subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
return;
case SCALAR_QUERY:
// to a constant expression.
if (!config.isExpand()) {
return;
}
call = (SqlBasicCall) subQuery.node;
query = call.operand(0);
converted = convertExists(query, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
assert !converted.indicator;
if (convertNonCorrelatedSubQuery(subQuery, bb, converted.r, false)) {
return;
}
rel = convertToSingleValueSubq(query, converted.r);
subQuery.expr = bb.register(rel, JoinRelType.LEFT);
return;
case SELECT:
// This is used when converting multiset queries:
//
// select * from unnest(select multiset[deptno] from emps);
//
converted = convertExists(subQuery.node, RelOptUtil.SubQueryType.SCALAR, subQuery.logic, true, null);
assert !converted.indicator;
subQuery.expr = bb.register(converted.r, JoinRelType.LEFT);
return;
default:
throw new AssertionError("unexpected kind of sub-query: " + subQuery.node);
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlNode in project calcite by apache.
the class SqlToRelConverter method convertInToOr.
/**
* Converts "x IN (1, 2, ...)" to "x=1 OR x=2 OR ...".
*
* @param leftKeys LHS
* @param valuesList RHS
* @param op The operator (IN, NOT IN, > SOME, ...)
* @return converted expression
*/
private RexNode convertInToOr(final Blackboard bb, final List<RexNode> leftKeys, SqlNodeList valuesList, SqlInOperator op) {
final List<RexNode> comparisons = new ArrayList<>();
for (SqlNode rightVals : valuesList) {
RexNode rexComparison;
final SqlOperator comparisonOp;
if (op instanceof SqlQuantifyOperator) {
comparisonOp = RelOptUtil.op(((SqlQuantifyOperator) op).comparisonKind, SqlStdOperatorTable.EQUALS);
} else {
comparisonOp = SqlStdOperatorTable.EQUALS;
}
if (leftKeys.size() == 1) {
rexComparison = rexBuilder.makeCall(comparisonOp, leftKeys.get(0), ensureSqlType(leftKeys.get(0).getType(), bb.convertExpression(rightVals)));
} else {
assert rightVals instanceof SqlCall;
final SqlBasicCall call = (SqlBasicCall) rightVals;
assert (call.getOperator() instanceof SqlRowOperator) && call.operandCount() == leftKeys.size();
rexComparison = RexUtil.composeConjunction(rexBuilder, Iterables.transform(Pair.zip(leftKeys, call.getOperandList()), new Function<Pair<RexNode, SqlNode>, RexNode>() {
public RexNode apply(Pair<RexNode, SqlNode> pair) {
return rexBuilder.makeCall(comparisonOp, pair.left, ensureSqlType(pair.left.getType(), bb.convertExpression(pair.right)));
}
}), false);
}
comparisons.add(rexComparison);
}
switch(op.kind) {
case ALL:
return RexUtil.composeConjunction(rexBuilder, comparisons, true);
case NOT_IN:
return rexBuilder.makeCall(SqlStdOperatorTable.NOT, RexUtil.composeDisjunction(rexBuilder, comparisons, true));
case IN:
case SOME:
return RexUtil.composeDisjunction(rexBuilder, comparisons, true);
default:
throw new AssertionError();
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlNode in project calcite by apache.
the class SqlToRelConverter method convertWhere.
/**
* Converts a WHERE clause.
*
* @param bb Blackboard
* @param where WHERE clause, may be null
*/
private void convertWhere(final Blackboard bb, final SqlNode where) {
if (where == null) {
return;
}
SqlNode newWhere = pushDownNotForIn(bb.scope, where);
replaceSubQueries(bb, newWhere, RelOptUtil.Logic.UNKNOWN_AS_FALSE);
final RexNode convertedWhere = bb.convertExpression(newWhere);
final RexNode convertedWhere2 = RexUtil.removeNullabilityCast(typeFactory, convertedWhere);
// only allocate filter if the condition is not TRUE
if (convertedWhere2.isAlwaysTrue()) {
return;
}
final RelFactories.FilterFactory factory = RelFactories.DEFAULT_FILTER_FACTORY;
final RelNode filter = factory.createFilter(bb.root, convertedWhere2);
final RelNode r;
final CorrelationUse p = getCorrelationUse(bb, filter);
if (p != null) {
assert p.r instanceof Filter;
Filter f = (Filter) p.r;
r = LogicalFilter.create(f.getInput(), f.getCondition(), ImmutableSet.of(p.id));
} else {
r = filter;
}
bb.setRoot(r, false);
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlNode in project calcite by apache.
the class SqlToRelConverter method convertRowValues.
private RelNode convertRowValues(Blackboard bb, SqlNode rowList, Collection<SqlNode> rows, boolean allowLiteralsOnly, 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 rowType;
if (targetRowType != null) {
rowType = targetRowType;
} else {
rowType = SqlTypeUtil.promoteToRowType(typeFactory, validator.getValidatedNodeType(rowList), 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.operands)) {
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.add(resultRel);
return resultRel;
}
use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.sql.SqlNode in project calcite by apache.
the class StandardConvertletTable method convertCast.
protected RexNode convertCast(SqlRexContext cx, final SqlCall call) {
RelDataTypeFactory typeFactory = cx.getTypeFactory();
assert call.getKind() == SqlKind.CAST;
final SqlNode left = call.operand(0);
final SqlNode right = call.operand(1);
if (right instanceof SqlIntervalQualifier) {
final SqlIntervalQualifier intervalQualifier = (SqlIntervalQualifier) right;
if (left instanceof SqlIntervalLiteral) {
RexLiteral sourceInterval = (RexLiteral) cx.convertExpression(left);
BigDecimal sourceValue = (BigDecimal) sourceInterval.getValue();
RexLiteral castedInterval = cx.getRexBuilder().makeIntervalLiteral(sourceValue, intervalQualifier);
return castToValidatedType(cx, call, castedInterval);
} else if (left instanceof SqlNumericLiteral) {
RexLiteral sourceInterval = (RexLiteral) cx.convertExpression(left);
BigDecimal sourceValue = (BigDecimal) sourceInterval.getValue();
final BigDecimal multiplier = intervalQualifier.getUnit().multiplier;
sourceValue = sourceValue.multiply(multiplier);
RexLiteral castedInterval = cx.getRexBuilder().makeIntervalLiteral(sourceValue, intervalQualifier);
return castToValidatedType(cx, call, castedInterval);
}
return castToValidatedType(cx, call, cx.convertExpression(left));
}
SqlDataTypeSpec dataType = (SqlDataTypeSpec) right;
if (SqlUtil.isNullLiteral(left, false)) {
return cx.convertExpression(left);
}
RexNode arg = cx.convertExpression(left);
RelDataType type = dataType.deriveType(typeFactory);
if (arg.getType().isNullable()) {
type = typeFactory.createTypeWithNullability(type, true);
}
if (null != dataType.getCollectionsTypeName()) {
final RelDataType argComponentType = arg.getType().getComponentType();
final RelDataType componentType = type.getComponentType();
if (argComponentType.isStruct() && !componentType.isStruct()) {
RelDataType tt = typeFactory.builder().add(argComponentType.getFieldList().get(0).getName(), componentType).build();
tt = typeFactory.createTypeWithNullability(tt, componentType.isNullable());
boolean isn = type.isNullable();
type = typeFactory.createMultisetType(tt, -1);
type = typeFactory.createTypeWithNullability(type, isn);
}
}
return cx.getRexBuilder().makeCast(type, arg);
}
Aggregations