Skip to content

Commit ea67822

Browse files
committed
[CALCITE-7112] Eliminate nested calls for idempotent unary functions upper/lower/abs
1 parent 0071f17 commit ea67822

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

core/src/main/java/org/apache/calcite/rex/RexSimplify.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555

5656
import java.math.BigDecimal;
5757
import java.util.ArrayList;
58+
import java.util.Arrays;
5859
import java.util.BitSet;
5960
import java.util.Collection;
6061
import java.util.Collections;
@@ -88,6 +89,9 @@ public class RexSimplify {
8889

8990
private static final Strong STRONG = new Strong();
9091

92+
private static final List<SqlOperator> IDEMOTENT_UNARY_FUNCTIONS =
93+
Arrays.asList(SqlStdOperatorTable.UPPER, SqlStdOperatorTable.LOWER, SqlStdOperatorTable.ABS);
94+
9195
/**
9296
* Creates a RexSimplify.
9397
*
@@ -333,7 +337,9 @@ RexNode simplify(RexNode e, RexUnknownAs unknownAs) {
333337
return simplifyM2v((RexCall) e);
334338
default:
335339
if (e.getClass() == RexCall.class) {
336-
return simplifyGenericNode((RexCall) e);
340+
RexCall rexCall = (RexCall) e;
341+
rexCall = simplifUnaryFunction(rexCall);
342+
return simplifyGenericNode(rexCall);
337343
} else {
338344
return e;
339345
}
@@ -397,6 +403,22 @@ RexNode isFalse(RexNode e) {
397403
: rexBuilder.makeCall(SqlStdOperatorTable.IS_FALSE, e);
398404
}
399405

406+
/**
407+
* Runs simplification unary function by eliminating idempotent.
408+
*/
409+
private RexCall simplifUnaryFunction(RexCall rexCall) {
410+
while (IDEMOTENT_UNARY_FUNCTIONS.contains(rexCall.getOperator())
411+
&& rexCall.getOperands().get(0) instanceof RexCall) {
412+
RexCall subRexCall = (RexCall) rexCall.getOperands().get(0);
413+
if (rexCall.getOperator() == subRexCall.getOperator()) {
414+
rexCall = subRexCall;
415+
} else {
416+
break;
417+
}
418+
}
419+
return rexCall;
420+
}
421+
400422
/**
401423
* Runs simplification inside a non-specialized node.
402424
*/

core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.calcite.rex.RexSimplify;
2525
import org.apache.calcite.rex.RexUnknownAs;
2626
import org.apache.calcite.sql.SqlKind;
27+
import org.apache.calcite.sql.SqlOperator;
2728
import org.apache.calcite.sql.fun.SqlStdOperatorTable;
2829
import org.apache.calcite.sql.type.SqlTypeName;
2930
import org.apache.calcite.util.DateString;
@@ -35,9 +36,13 @@
3536

3637
import org.junit.jupiter.api.Test;
3738

39+
import java.util.Arrays;
40+
import java.util.List;
41+
3842
import static org.apache.calcite.test.RexImplicationCheckerFixtures.Fixture;
3943

4044
import static org.hamcrest.CoreMatchers.is;
45+
import static org.hamcrest.CoreMatchers.not;
4146
import static org.hamcrest.MatcherAssert.assertThat;
4247
import static org.hamcrest.Matchers.hasToString;
4348

@@ -361,6 +366,57 @@ public class RexImplicationCheckerTest {
361366
hasToString("2014"));
362367
}
363368

369+
/** Test case for
370+
* <a href="https://issues.apache.org/jira/browse/CALCITE-7112">[CALCITE-7112]
371+
* Eliminate nested calls for idempotent unary functions upper/lower/abs</a>. */
372+
@Test void testSimplifyIdempotentUnaryFunctions() {
373+
// test for upper/lower functions
374+
final Fixture f = new Fixture();
375+
List<SqlOperator> testOeratorList =
376+
Arrays.asList(SqlStdOperatorTable.UPPER, SqlStdOperatorTable.LOWER);
377+
for (SqlOperator operator : testOeratorList) {
378+
RexCall innerCall =
379+
(RexCall) f.rexBuilder
380+
.makeCall(operator, f.rexBuilder.makeLiteral("Calcite Test"));
381+
RexCall outerCall =
382+
(RexCall) f.rexBuilder.makeCall(operator, innerCall);
383+
RexCall simplifiedInnerCall =
384+
(RexCall) f.simplify.simplifyPreservingType(outerCall,
385+
RexUnknownAs.UNKNOWN, true);
386+
387+
assertThat(((RexLiteral) simplifiedInnerCall.getOperands().get(0))
388+
.getValue(),
389+
is(((RexLiteral) innerCall.getOperands().get(0)).getValue()));
390+
}
391+
392+
// test for abs function
393+
RelDataType intType = f.rexBuilder.getTypeFactory().createSqlType(SqlTypeName.INTEGER);
394+
RexCall innerCall =
395+
(RexCall) f.rexBuilder
396+
.makeCall(SqlStdOperatorTable.ABS, f.rexBuilder.makeLiteral(12, intType));
397+
RexCall outerCall =
398+
(RexCall) f.rexBuilder
399+
.makeCall(SqlStdOperatorTable.ABS, innerCall);
400+
RexCall simplifiedInnerCall =
401+
(RexCall) f.simplify.simplifyPreservingType(outerCall,
402+
RexUnknownAs.UNKNOWN, true);
403+
404+
assertThat(((RexLiteral) simplifiedInnerCall.getOperands().get(0)).getValue(),
405+
is(((RexLiteral) innerCall.getOperands().get(0)).getValue()));
406+
407+
// negative test
408+
innerCall = (RexCall) f.rexBuilder
409+
.makeCall(SqlStdOperatorTable.UPPER, f.rexBuilder.makeLiteral("Calcite Test"));
410+
outerCall = (RexCall) f.rexBuilder.makeCall(SqlStdOperatorTable.LOWER, innerCall);
411+
simplifiedInnerCall = (RexCall) f.simplify
412+
.simplifyPreservingType(outerCall, RexUnknownAs.UNKNOWN, true);
413+
414+
assertThat(simplifiedInnerCall.getOperands().get(0),
415+
not(((RexLiteral) innerCall.getOperands().get(0)).getValue()));
416+
assertThat(((RexCall) simplifiedInnerCall.getOperands().get(0)).getOperands().get(0),
417+
is(innerCall.getOperands().get(0)));
418+
}
419+
364420
/** Test case for
365421
* <a href="https://issues.apache.org/jira/browse/CALCITE-7042">[CALCITE-7042]
366422
* Eliminate nested TRIM calls, exploiting the fact that TRIM is idempotent</a>. */

0 commit comments

Comments
 (0)