This is an automated email from the ASF dual-hosted git repository. jhyde pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/calcite.git
commit 181dd402aefc801e2b704e5640b28fe7d7cd803f Author: Julian Hyde <[email protected]> AuthorDate: Wed May 17 21:48:26 2023 -0700 [CALCITE-5790] Validator should disallow a query with * but no FROM clause The query "SELECT *" should throw the error "SELECT * requires a FROM clause". --- .../apache/calcite/runtime/CalciteResource.java | 3 +++ .../calcite/sql/validate/SqlValidatorImpl.java | 12 ++++++----- .../calcite/runtime/CalciteResource.properties | 1 + .../org/apache/calcite/test/SqlValidatorTest.java | 25 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java index d515c8e024..fc8fd6fb1e 100644 --- a/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java +++ b/core/src/main/java/org/apache/calcite/runtime/CalciteResource.java @@ -774,6 +774,9 @@ public interface CalciteResource { @BaseMessage("SELECT must have a FROM clause") ExInst<SqlValidatorException> selectMissingFrom(); + @BaseMessage("SELECT * requires a FROM clause") + ExInst<SqlValidatorException> selectStarRequiresFrom(); + @BaseMessage("Group function ''{0}'' can only appear in GROUP BY clause") ExInst<SqlValidatorException> groupFunctionMustAppearInGroupByClause(String funcName); 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 1f65494f71..3ca5925ec2 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 @@ -626,6 +626,11 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { final SqlParserPos startPosition = identifier.getParserPosition(); switch (identifier.names.size()) { case 1: + SqlNode from = scope.getNode().getFrom(); + if (from == null) { + throw newValidationError(identifier, RESOURCE.selectStarRequiresFrom()); + } + boolean hasDynamicStruct = false; for (ScopeChild child : scope.children) { final int before = fields.size(); @@ -647,8 +652,8 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { scope, includeSystemVars); } else { - final SqlNode from = SqlNonNullableAccessors.getNode(child); - final SqlValidatorNamespace fromNs = getNamespaceOrThrow(from, scope); + final SqlNode from2 = SqlNonNullableAccessors.getNode(child); + final SqlValidatorNamespace fromNs = getNamespaceOrThrow(from2, scope); final RelDataType rowType = fromNs.getRowType(); for (RelDataTypeField field : rowType.getFieldList()) { String columnName = field.getName(); @@ -686,9 +691,6 @@ public class SqlValidatorImpl implements SqlValidatorWithHints { // If NATURAL JOIN or USING is present, move key fields to the front of // the list, per standard SQL. Disabled if there are dynamic fields. if (!hasDynamicStruct || Bug.CALCITE_2400_FIXED) { - SqlNode from = - requireNonNull(scope.getNode().getFrom(), - () -> "getFrom for " + scope.getNode()); // If some fields before star identifier, // we should move offset. int offset = calculatePermuteOffset(selectItems); diff --git a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties index d4e9f29208..c402732059 100644 --- a/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties +++ b/core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties @@ -254,6 +254,7 @@ FilterMustBeBoolean=FILTER expression must be of type BOOLEAN CannotStreamResultsForNonStreamingInputs=Cannot stream results of a query with no streaming inputs: ''{0}''. At least one input should be convertible to a stream MinusNotAllowed=MINUS is not allowed under the current SQL conformance level SelectMissingFrom=SELECT must have a FROM clause +SelectStarRequiresFrom=SELECT * requires a FROM clause GroupFunctionMustAppearInGroupByClause=Group function ''{0}'' can only appear in GROUP BY clause AuxiliaryWithoutMatchingGroupCall=Call to auxiliary group function ''{0}'' must have matching call to group function ''{1}'' in GROUP BY clause PivotAggMalformed=Measure expression in PIVOT must use aggregate function diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java index 3a742499ae..6c132175f8 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java @@ -3744,6 +3744,31 @@ public class SqlValidatorTest extends SqlValidatorTestCase { .fails("(?s).*Encountered \".\" at .*"); } + @Test void testStarWithoutFromFails() { + final String selectStarRequiresAFromClause = + "SELECT \\* requires a FROM clause"; + sql("select ^*^") + .fails(selectStarRequiresAFromClause); + sql("select * from (select 2 as two)") + .type("RecordType(INTEGER NOT NULL TWO) NOT NULL"); + sql("select ^e^.*") + .fails("Unknown identifier 'E'"); + sql("select ^*^, 2 as two") + .fails(selectStarRequiresAFromClause); + sql("select 2 as two, ^*^") + .fails(selectStarRequiresAFromClause); + sql("select 3 as three union select ^*^ union select 4 as four") + .fails(selectStarRequiresAFromClause); + sql("select sum(1) as someone, ^*^") + .fails(selectStarRequiresAFromClause); + sql("select c from (select ^*^) as t(c)") + .fails(selectStarRequiresAFromClause); + sql("select 2 as two\n" + + "from emp as e\n" + + "where exists (select e.*)") + .type("RecordType(INTEGER NOT NULL TWO) NOT NULL"); + } + @Test void testAsColumnList() { sql("select d.a, b from dept as d(a, b)").ok(); sql("select d.^deptno^ from dept as d(a, b)")
