From d74b283f56a0043202af8ad95080ca21c70b8baa Mon Sep 17 00:00:00 2001 From: Norman Jordan Date: Mon, 27 May 2024 08:53:38 -0700 Subject: [PATCH] [CALCITE-6369] Expanding "star" gives ArrayIndexOutOfBoundsException with redundant columns and USING Fixes expanding * when columns are also specified in the projection list --- .../sql/validate/SqlValidatorImpl.java | 3 +- .../rel/rel2sql/RelToSqlConverterTest.java | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java index f9d9e951df04..7d2aedb4ca7d 100644 --- a/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java +++ b/core/src/main/java/org/apache/calcite/sql/validate/SqlValidatorImpl.java @@ -666,6 +666,7 @@ private boolean expandStar(List selectItems, Set aliases, if (!identifier.isStar()) { return false; } + final int originalSize = selectItems.size(); final SqlParserPos startPosition = identifier.getParserPosition(); switch (identifier.names.size()) { case 1: @@ -736,7 +737,7 @@ private boolean expandStar(List selectItems, Set aliases, if (!hasDynamicStruct || Bug.CALCITE_2400_FIXED) { // If some fields before star identifier, // we should move offset. - int offset = calculatePermuteOffset(selectItems); + int offset = Math.min(calculatePermuteOffset(selectItems), originalSize); new Permute(from, offset).permute(selectItems, fields); } return true; diff --git a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java index af4ff86794d7..2ba73ae8d78f 100644 --- a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java +++ b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java @@ -8318,6 +8318,74 @@ private void checkLiteral2(String expression, String expected) { .withPostgresql().ok(expectedQuery); } + /** Test case for + * [CALCITE-6369] + * Expanding "star" gives ArrayIndexOutOfBoundsException with redundant columns and USING. + */ + @Test void testUsingClauseWithStarInProjection() { + final String query = "select \"employee_id\", * from \"employee\" e0 join " + + "\"employee\" e1 using (\"employee_id\")"; + final String expectedQuery = "SELECT \"employee\".\"employee_id\", " + + "\"employee\".\"employee_id\" AS \"employee_id0\", \"employee\".\"full_name\", " + + "\"employee\".\"first_name\", \"employee\".\"last_name\", \"employee\".\"position_id\", " + + "\"employee\".\"position_title\", \"employee\".\"store_id\", " + + "\"employee\".\"department_id\", \"employee\".\"birth_date\", " + + "\"employee\".\"hire_date\", \"employee\".\"end_date\", \"employee\".\"salary\", " + + "\"employee\".\"supervisor_id\", \"employee\".\"education_level\", " + + "\"employee\".\"marital_status\", \"employee\".\"gender\", " + + "\"employee\".\"management_role\", \"employee0\".\"full_name\" AS \"full_name0\", " + + "\"employee0\".\"first_name\" AS \"first_name0\", " + + "\"employee0\".\"last_name\" AS \"last_name0\", " + + "\"employee0\".\"position_id\" AS \"position_id0\", " + + "\"employee0\".\"position_title\" AS \"position_title0\", " + + "\"employee0\".\"store_id\" AS \"store_id0\", " + + "\"employee0\".\"department_id\" AS \"department_id0\", " + + "\"employee0\".\"birth_date\" AS \"birth_date0\", " + + "\"employee0\".\"hire_date\" AS \"hire_date0\", " + + "\"employee0\".\"end_date\" AS \"end_date0\", \"employee0\".\"salary\" AS \"salary0\", " + + "\"employee0\".\"supervisor_id\" AS \"supervisor_id0\", " + + "\"employee0\".\"education_level\" AS \"education_level0\", " + + "\"employee0\".\"marital_status\" AS \"marital_status0\", " + + "\"employee0\".\"gender\" AS \"gender0\", " + + "\"employee0\".\"management_role\" AS \"management_role0\"\n" + + "FROM \"foodmart\".\"employee\"\n" + + "INNER JOIN \"foodmart\".\"employee\" AS \"employee0\" ON " + + "\"employee\".\"employee_id\" = \"employee0\".\"employee_id\""; + sql(query).withPostgresql().ok(expectedQuery); + } + + @Test void testUsingClauseWithStarAndAsInProjection() { + final String query = "select \"employee_id\" as \"eid\", * from \"employee\" e0 join " + + "\"employee\" e1 using (\"employee_id\")"; + final String expectedQuery = "SELECT \"employee\".\"employee_id\" AS \"eid\", " + + "\"employee\".\"employee_id\", \"employee\".\"full_name\", \"employee\".\"first_name\", " + + "\"employee\".\"last_name\", \"employee\".\"position_id\", " + + "\"employee\".\"position_title\", \"employee\".\"store_id\", " + + "\"employee\".\"department_id\", \"employee\".\"birth_date\", " + + "\"employee\".\"hire_date\", \"employee\".\"end_date\", \"employee\".\"salary\", " + + "\"employee\".\"supervisor_id\", \"employee\".\"education_level\", " + + "\"employee\".\"marital_status\", \"employee\".\"gender\", " + + "\"employee\".\"management_role\", \"employee0\".\"full_name\" AS \"full_name0\", " + + "\"employee0\".\"first_name\" AS \"first_name0\", " + + "\"employee0\".\"last_name\" AS \"last_name0\", " + + "\"employee0\".\"position_id\" AS \"position_id0\", " + + "\"employee0\".\"position_title\" AS \"position_title0\", " + + "\"employee0\".\"store_id\" AS \"store_id0\", " + + "\"employee0\".\"department_id\" AS \"department_id0\", " + + "\"employee0\".\"birth_date\" AS \"birth_date0\", " + + "\"employee0\".\"hire_date\" AS \"hire_date0\", " + + "\"employee0\".\"end_date\" AS \"end_date0\", \"employee0\".\"salary\" AS \"salary0\", " + + "\"employee0\".\"supervisor_id\" AS \"supervisor_id0\", " + + "\"employee0\".\"education_level\" AS \"education_level0\", " + + "\"employee0\".\"marital_status\" AS \"marital_status0\", " + + "\"employee0\".\"gender\" AS \"gender0\", " + + "\"employee0\".\"management_role\" AS \"management_role0\"\n" + + "FROM \"foodmart\".\"employee\"\n" + + "INNER JOIN \"foodmart\".\"employee\" AS \"employee0\" ON " + + "\"employee\".\"employee_id\" = \"employee0\".\"employee_id\""; + sql(query).withPostgresql().ok(expectedQuery); + } + /** Fluid interface to run tests. */ static class Sql { private final CalciteAssert.SchemaSpec schemaSpec;