diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPivot.java b/core/src/main/java/org/apache/calcite/sql/SqlPivot.java index cb5fa4ee7497..6a082b143301 100644 --- a/core/src/main/java/org/apache/calcite/sql/SqlPivot.java +++ b/core/src/main/java/org/apache/calcite/sql/SqlPivot.java @@ -35,6 +35,8 @@ import java.util.function.BiConsumer; import java.util.stream.Collectors; +import static java.util.Objects.requireNonNull; + /** * Parse tree node that represents a PIVOT applied to a table reference * (or sub-query). @@ -195,5 +197,16 @@ static class Operator extends SqlSpecialOperator { Operator(SqlKind kind) { super(kind.name(), kind); } + + @Override public SqlCall createCall( + @Nullable SqlLiteral functionQualifier, + SqlParserPos pos, + @Nullable SqlNode... operands) { + assert operands.length == 4; + return new SqlPivot(pos, requireNonNull(operands[0], "query"), + requireNonNull((SqlNodeList) operands[1], "aggList"), + requireNonNull((SqlNodeList) operands[2], "axisList"), + requireNonNull((SqlNodeList) operands[3], "inList")); + } } } diff --git a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java index eab5658b347f..223a2b0bd794 100644 --- a/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java +++ b/testkit/src/main/java/org/apache/calcite/sql/parser/SqlParserTest.java @@ -9044,6 +9044,28 @@ private static Consumer> checkWarnings( sql(sql).ok(expected); } + @Test void testPivotThroughShuttle() { + final String sql = "" + + "SELECT *\n" + + "FROM (SELECT job, deptno FROM \"EMP\")\n" + + "PIVOT (COUNT(*) AS \"COUNT\" FOR deptno IN (10, 50, 20))"; + final String expected = "" + + "SELECT *\n" + + "FROM (SELECT `JOB`, `DEPTNO`\n" + + "FROM `EMP`) PIVOT (COUNT(*) AS `COUNT` FOR `DEPTNO` IN (10, 50, 20))"; + final SqlNode sqlNode = sql(sql).node(); + + final SqlNode shuttled = sqlNode.accept(new SqlShuttle() { + @Override public @Nullable SqlNode visit(final SqlCall call) { + // Handler always creates a new copy of 'call' + CallCopyingArgHandler argHandler = new CallCopyingArgHandler(call, true); + call.getOperator().acceptCall(this, call, false, argHandler); + return argHandler.result(); + } + }); + assertThat(toLinux(shuttled.toString()), is(expected)); + } + @Test void testMatchRecognize1() { final String sql = "select *\n" + " from t match_recognize\n"