zoudan commented on code in PR #2854:
URL: https://github.com/apache/calcite/pull/2854#discussion_r1139988511
##########
core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java:
##########
@@ -4049,6 +4081,101 @@ private static class HopImplementor implements
TableFunctionCallImplementor {
}
}
+ /**
+ * Implements
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16">
+ * ANY/SOME</a> and
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.17">ALL</a>
+ * operators when the argument is an array or multiset expression.
+ */
+ private static class QuantifyCollectionImplementor extends
AbstractRexCallImplementor {
+ private final SqlBinaryOperator binaryOperator;
+ private final RexCallImplementor binaryImplementor;
+
+ QuantifyCollectionImplementor(SqlBinaryOperator binaryOperator,
+ RexCallImplementor binaryImplementor) {
+ super(NullPolicy.ANY, false);
+ this.binaryOperator = binaryOperator;
+ this.binaryImplementor = binaryImplementor;
+ }
+
+ @Override String getVariableName() {
+ return "quantify";
+ }
+
+ @Override Expression implementSafe(RexToLixTranslator translator, RexCall
call,
+ List<Expression> argValueList) {
+ Expression left = argValueList.get(0);
+ Expression right = argValueList.get(1);
+ final RelDataType rightComponentType =
+
requireNonNull(call.getOperands().get(1).getType().getComponentType());
+ // If the array expression yields a null array, the result of SOME|ALL
will be null
+ if (rightComponentType.getSqlTypeName() == SqlTypeName.NULL) {
+ return NULL_EXPR;
+ }
+
+ // The expression generated by this method will look as follows:
+ // final T _quantify_left_value = <left_value>
+ // <Function1|Predicate1> lambda =
+ // new org.apache.calcite.linq4j.function.<Function1|Predicate1>() {
+ // public Boolean apply(T el) {
+ // return <binaryImplementor code>(_quantify_left_value, el);
+ // }
+ // }
+ // If the lambda returns java.lang.Boolean then the lambda can return
null.
+ // In this case nullableExists or nullableSome should be used:
+ // return
org.apache.calcite.runtime.SqlFunctions.<nullableExists|nullableSome>(_list,
lambda)
+ // otherwise:
+ // return
org.apache.calcite.linq4j.function.Functions.<exists|all>(_list, lambda)
+ BlockBuilder lambdaBuilder = new BlockBuilder();
+ final ParameterExpression leftExpr =
+ Expressions.parameter(left.getType(),
+ translator.getBlockBuilder().newName("_" + getVariableName() +
"_left_value"));
+ // left should have final modifier otherwise it can not be passed to
lambda
+ translator.getBlockBuilder().add(Expressions.declare(Modifier.FINAL,
leftExpr, left));
+ RexNode leftRex = call.getOperands().get(0);
+ final ParameterExpression lambdaArg =
+
Expressions.parameter(translator.typeFactory.getJavaClass(rightComponentType),
"el");
+ final RexCall binaryImplementorRexCall =
+ (RexCall) translator.builder.makeCall(binaryOperator, leftRex,
+ translator.builder.makeDynamicParam(rightComponentType, 0));
+ final List<RexToLixTranslator.Result> binaryImplementorArgs =
+ ImmutableList.of(
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, leftExpr), leftExpr),
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, lambdaArg), lambdaArg));
+ final RexToLixTranslator.Result condition =
+ binaryImplementor.implement(translator, binaryImplementorRexCall,
binaryImplementorArgs);
+ lambdaBuilder.add(Expressions.return_(null, condition.valueVariable));
+ final FunctionExpression<?> predicate =
+ Expressions.lambda(lambdaBuilder.toBlock(), lambdaArg);
+ return Expressions.call(getMethod(condition.valueVariable.getType(),
call.getKind()), right,
+ predicate);
+ }
+
+ private Method getMethod(Type comparisonReturnType, SqlKind kind) {
+ switch (kind) {
+ case SOME:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_EXISTS.method
+ // if the array contains any null elements and no true comparison
result is obtained,
+ // the result of SOME will be null, not false.
+ : BuiltInMethod.COLLECTION_NULLABLE_EXISTS.method;
+ case ALL:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_ALL.method
+ // if the array contains any null elements and no false comparison
result is obtained,
+ // the result of ALL will be null, not true.
+ : BuiltInMethod.COLLECTION_NULLABLE_ALL.method;
+ default:
+ throw new IllegalArgumentException("Unknown quantify operator" + kind
+ + ". Only support SOME,ALL.");
Review Comment:
add a space after comma
##########
core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java:
##########
@@ -5451,7 +5461,11 @@ ImmutableList<RelNode> retrieveCursors() {
case CURSOR:
case IN:
case NOT_IN:
- subQuery = requireNonNull(getSubQuery(expr, null));
+ subQuery = getSubQuery(expr, null);
+ if (subQuery == null && (kind == SqlKind.SOME || kind == SqlKind.ALL))
{
+ break;
+ }
+ assert subQuery != null;
Review Comment:
Agree with @bchapuis, it is meaningless to call 'assert' here.
##########
core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java:
##########
@@ -4049,6 +4081,101 @@ private static class HopImplementor implements
TableFunctionCallImplementor {
}
}
+ /**
+ * Implements
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16">
+ * ANY/SOME</a> and
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.17">ALL</a>
+ * operators when the argument is an array or multiset expression.
+ */
+ private static class QuantifyCollectionImplementor extends
AbstractRexCallImplementor {
+ private final SqlBinaryOperator binaryOperator;
+ private final RexCallImplementor binaryImplementor;
+
+ QuantifyCollectionImplementor(SqlBinaryOperator binaryOperator,
+ RexCallImplementor binaryImplementor) {
+ super(NullPolicy.ANY, false);
+ this.binaryOperator = binaryOperator;
+ this.binaryImplementor = binaryImplementor;
+ }
+
+ @Override String getVariableName() {
+ return "quantify";
+ }
+
+ @Override Expression implementSafe(RexToLixTranslator translator, RexCall
call,
+ List<Expression> argValueList) {
+ Expression left = argValueList.get(0);
+ Expression right = argValueList.get(1);
+ final RelDataType rightComponentType =
+
requireNonNull(call.getOperands().get(1).getType().getComponentType());
+ // If the array expression yields a null array, the result of SOME|ALL
will be null
+ if (rightComponentType.getSqlTypeName() == SqlTypeName.NULL) {
+ return NULL_EXPR;
+ }
+
+ // The expression generated by this method will look as follows:
+ // final T _quantify_left_value = <left_value>
+ // <Function1|Predicate1> lambda =
+ // new org.apache.calcite.linq4j.function.<Function1|Predicate1>() {
+ // public Boolean apply(T el) {
+ // return <binaryImplementor code>(_quantify_left_value, el);
+ // }
+ // }
+ // If the lambda returns java.lang.Boolean then the lambda can return
null.
+ // In this case nullableExists or nullableSome should be used:
+ // return
org.apache.calcite.runtime.SqlFunctions.<nullableExists|nullableSome>(_list,
lambda)
+ // otherwise:
+ // return
org.apache.calcite.linq4j.function.Functions.<exists|all>(_list, lambda)
+ BlockBuilder lambdaBuilder = new BlockBuilder();
+ final ParameterExpression leftExpr =
+ Expressions.parameter(left.getType(),
+ translator.getBlockBuilder().newName("_" + getVariableName() +
"_left_value"));
+ // left should have final modifier otherwise it can not be passed to
lambda
+ translator.getBlockBuilder().add(Expressions.declare(Modifier.FINAL,
leftExpr, left));
+ RexNode leftRex = call.getOperands().get(0);
+ final ParameterExpression lambdaArg =
+
Expressions.parameter(translator.typeFactory.getJavaClass(rightComponentType),
"el");
+ final RexCall binaryImplementorRexCall =
+ (RexCall) translator.builder.makeCall(binaryOperator, leftRex,
+ translator.builder.makeDynamicParam(rightComponentType, 0));
+ final List<RexToLixTranslator.Result> binaryImplementorArgs =
+ ImmutableList.of(
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, leftExpr), leftExpr),
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, lambdaArg), lambdaArg));
+ final RexToLixTranslator.Result condition =
+ binaryImplementor.implement(translator, binaryImplementorRexCall,
binaryImplementorArgs);
+ lambdaBuilder.add(Expressions.return_(null, condition.valueVariable));
+ final FunctionExpression<?> predicate =
+ Expressions.lambda(lambdaBuilder.toBlock(), lambdaArg);
+ return Expressions.call(getMethod(condition.valueVariable.getType(),
call.getKind()), right,
+ predicate);
+ }
+
+ private Method getMethod(Type comparisonReturnType, SqlKind kind) {
+ switch (kind) {
+ case SOME:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_EXISTS.method
+ // if the array contains any null elements and no true comparison
result is obtained,
+ // the result of SOME will be null, not false.
+ : BuiltInMethod.COLLECTION_NULLABLE_EXISTS.method;
+ case ALL:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_ALL.method
+ // if the array contains any null elements and no false comparison
result is obtained,
+ // the result of ALL will be null, not true.
+ : BuiltInMethod.COLLECTION_NULLABLE_ALL.method;
+ default:
+ throw new IllegalArgumentException("Unknown quantify operator" + kind
+ + ". Only support SOME,ALL.");
+ }
+ }
+ }
+
Review Comment:
remove one empty line
##########
core/src/main/java/org/apache/calcite/adapter/enumerable/RexImpTable.java:
##########
@@ -4049,6 +4081,101 @@ private static class HopImplementor implements
TableFunctionCallImplementor {
}
}
+ /**
+ * Implements
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.16">
+ * ANY/SOME</a> and
+ * <a
href="https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.30.17">ALL</a>
+ * operators when the argument is an array or multiset expression.
+ */
+ private static class QuantifyCollectionImplementor extends
AbstractRexCallImplementor {
+ private final SqlBinaryOperator binaryOperator;
+ private final RexCallImplementor binaryImplementor;
+
+ QuantifyCollectionImplementor(SqlBinaryOperator binaryOperator,
+ RexCallImplementor binaryImplementor) {
+ super(NullPolicy.ANY, false);
+ this.binaryOperator = binaryOperator;
+ this.binaryImplementor = binaryImplementor;
+ }
+
+ @Override String getVariableName() {
+ return "quantify";
+ }
+
+ @Override Expression implementSafe(RexToLixTranslator translator, RexCall
call,
+ List<Expression> argValueList) {
+ Expression left = argValueList.get(0);
+ Expression right = argValueList.get(1);
+ final RelDataType rightComponentType =
+
requireNonNull(call.getOperands().get(1).getType().getComponentType());
+ // If the array expression yields a null array, the result of SOME|ALL
will be null
+ if (rightComponentType.getSqlTypeName() == SqlTypeName.NULL) {
+ return NULL_EXPR;
+ }
+
+ // The expression generated by this method will look as follows:
+ // final T _quantify_left_value = <left_value>
+ // <Function1|Predicate1> lambda =
+ // new org.apache.calcite.linq4j.function.<Function1|Predicate1>() {
+ // public Boolean apply(T el) {
+ // return <binaryImplementor code>(_quantify_left_value, el);
+ // }
+ // }
+ // If the lambda returns java.lang.Boolean then the lambda can return
null.
+ // In this case nullableExists or nullableSome should be used:
+ // return
org.apache.calcite.runtime.SqlFunctions.<nullableExists|nullableSome>(_list,
lambda)
+ // otherwise:
+ // return
org.apache.calcite.linq4j.function.Functions.<exists|all>(_list, lambda)
+ BlockBuilder lambdaBuilder = new BlockBuilder();
+ final ParameterExpression leftExpr =
+ Expressions.parameter(left.getType(),
+ translator.getBlockBuilder().newName("_" + getVariableName() +
"_left_value"));
+ // left should have final modifier otherwise it can not be passed to
lambda
+ translator.getBlockBuilder().add(Expressions.declare(Modifier.FINAL,
leftExpr, left));
+ RexNode leftRex = call.getOperands().get(0);
+ final ParameterExpression lambdaArg =
+
Expressions.parameter(translator.typeFactory.getJavaClass(rightComponentType),
"el");
+ final RexCall binaryImplementorRexCall =
+ (RexCall) translator.builder.makeCall(binaryOperator, leftRex,
+ translator.builder.makeDynamicParam(rightComponentType, 0));
+ final List<RexToLixTranslator.Result> binaryImplementorArgs =
+ ImmutableList.of(
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, leftExpr), leftExpr),
+ new RexToLixTranslator.Result(
+ genIsNullStatement(translator, lambdaArg), lambdaArg));
+ final RexToLixTranslator.Result condition =
+ binaryImplementor.implement(translator, binaryImplementorRexCall,
binaryImplementorArgs);
+ lambdaBuilder.add(Expressions.return_(null, condition.valueVariable));
+ final FunctionExpression<?> predicate =
+ Expressions.lambda(lambdaBuilder.toBlock(), lambdaArg);
+ return Expressions.call(getMethod(condition.valueVariable.getType(),
call.getKind()), right,
+ predicate);
+ }
+
+ private Method getMethod(Type comparisonReturnType, SqlKind kind) {
+ switch (kind) {
+ case SOME:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_EXISTS.method
+ // if the array contains any null elements and no true comparison
result is obtained,
+ // the result of SOME will be null, not false.
+ : BuiltInMethod.COLLECTION_NULLABLE_EXISTS.method;
+ case ALL:
+ return Primitive.is(comparisonReturnType)
+ ? BuiltInMethod.COLLECTION_ALL.method
+ // if the array contains any null elements and no false comparison
result is obtained,
+ // the result of ALL will be null, not true.
+ : BuiltInMethod.COLLECTION_NULLABLE_ALL.method;
+ default:
+ throw new IllegalArgumentException("Unknown quantify operator" + kind
Review Comment:
add space after `operator `
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]