Skip to content

Commit 16af9e2

Browse files
committed
[CALCITE-7331] Support the alias form SELECT * EXCEPT() for SELECT * EXCLUDE()
1 parent 77d561f commit 16af9e2

File tree

6 files changed

+93
-11
lines changed

6 files changed

+93
-11
lines changed

babel/src/test/java/org/apache/calcite/test/BabelTest.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,21 @@ names, is(
195195
});
196196

197197
fixture.withSql("select * exclude (empno, ^foo^) from emp")
198-
.fails("SELECT \\* EXCLUDE list contains unknown column\\(s\\): FOO");
198+
.fails("SELECT \\* EXCLUDE/EXCEPT list contains unknown column\\(s\\): FOO");
199+
200+
// Alias form: EXCEPT behaves the same as EXCLUDE
201+
fixture.withSql("select * except(empno, deptno) from emp")
202+
.type(type -> {
203+
final List<String> names = type.getFieldList().stream()
204+
.map(RelDataTypeField::getName)
205+
.collect(Collectors.toList());
206+
assertThat(
207+
names, is(
208+
ImmutableList.of("ENAME", "JOB", "MGR", "HIREDATE", "SAL", "COMM", "SLACKER")));
209+
});
210+
211+
fixture.withSql("select * except (empno, ^foo^) from emp")
212+
.fails("SELECT \\* EXCLUDE/EXCEPT list contains unknown column\\(s\\): FOO");
199213

200214
fixture.withSql("select e.* exclude(e.empno, e.ename, e.job, e.mgr)"
201215
+ " from emp e join dept d on e.deptno = d.deptno")
@@ -210,7 +224,23 @@ names, is(
210224

211225
fixture.withSql("select e.* exclude(e.empno, e.ename, e.job, e.mgr, ^d.deptno^)"
212226
+ " from emp e join dept d on e.deptno = d.deptno")
213-
.fails("SELECT \\* EXCLUDE list contains unknown column\\(s\\): D.DEPTNO");
227+
.fails("SELECT \\* EXCLUDE/EXCEPT list contains unknown column\\(s\\): D.DEPTNO");
228+
229+
// Alias form: EXCEPT for table-qualified star
230+
fixture.withSql("select e.* except(e.empno, e.ename, e.job, e.mgr)"
231+
+ " from emp e join dept d on e.deptno = d.deptno")
232+
.type(type -> {
233+
final List<String> names = type.getFieldList().stream()
234+
.map(RelDataTypeField::getName)
235+
.collect(Collectors.toList());
236+
assertThat(
237+
names, is(
238+
ImmutableList.of("HIREDATE", "SAL", "COMM", "DEPTNO", "SLACKER")));
239+
});
240+
241+
fixture.withSql("select e.* except(e.empno, e.ename, e.job, e.mgr, ^d.deptno^)"
242+
+ " from emp e join dept d on e.deptno = d.deptno")
243+
.fails("SELECT \\* EXCLUDE/EXCEPT list contains unknown column\\(s\\): D.DEPTNO");
214244

215245
fixture.withSql("select e.* exclude(e.empno, e.ename, e.job, e.mgr), d.* exclude(d.name)"
216246
+ " from emp e join dept d on e.deptno = d.deptno")
@@ -242,7 +272,7 @@ names, is(
242272

243273
// To verify that the exclude list contains all columns in the table
244274
fixture.withSql("select ^*^ exclude(deptno, name) from dept")
245-
.fails("SELECT \\* EXCLUDE list cannot exclude all columns");
275+
.fails("SELECT \\* EXCLUDE/EXCEPT list cannot exclude all columns");
246276
}
247277

248278
/** Tests that DATEADD, DATEDIFF, DATEPART, DATE_PART allow custom time

babel/src/test/resources/sql/select.iq

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,4 +234,56 @@ WHERE d.loc = 'CHICAGO';
234234

235235
!ok
236236

237+
# [CALCITE-7331] Support the alias form SELECT * EXCEPT() for SELECT * EXCLUDE()
238+
select 1 as x, 2 as y except (select 3 as a, 4 as b);
239+
+---+---+
240+
| X | Y |
241+
+---+---+
242+
| 1 | 2 |
243+
+---+---+
244+
(1 row)
245+
246+
!ok
247+
248+
with t(x, y) as (values(1, 2))
249+
select 1 as x, 2 as y except (y) from t;
250+
Non-query expression encountered in illegal context
251+
!error
252+
253+
with t(x, y) as (values(1, 2))
254+
select x except (x) from t;
255+
EXCLUDE/EXCEPT clause must follow a STAR expression
256+
!error
257+
258+
with t(x, y) as (values(1, 2))
259+
select * except (x) from t;
260+
+---+
261+
| Y |
262+
+---+
263+
| 2 |
264+
+---+
265+
(1 row)
266+
267+
!ok
268+
269+
select 1 as x, e.* except(e.empno, e.ename, e.job, e.mgr), d.* except(d.dname), 2 as y
270+
from emp e join dept d on e.deptno = d.deptno limit 1;
271+
+---+------------+---------+------+--------+---------+----------+---+
272+
| X | HIREDATE | SAL | COMM | DEPTNO | DEPTNO0 | LOC | Y |
273+
+---+------------+---------+------+--------+---------+----------+---+
274+
| 1 | 1981-06-09 | 2450.00 | | 10 | 10 | NEW YORK | 2 |
275+
+---+------------+---------+------+--------+---------+----------+---+
276+
(1 row)
277+
278+
!ok
279+
280+
select d1.* except(d1.dname) from dept d1 except(select d2.* except(d2.dname) from dept d2);
281+
+--------+-----+
282+
| DEPTNO | LOC |
283+
+--------+-----+
284+
+--------+-----+
285+
(0 rows)
286+
287+
!ok
288+
237289
# End select.iq

core/src/main/codegen/templates/Parser.jj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2049,7 +2049,7 @@ SqlNodeList StarExcludeList() :
20492049
SqlIdentifier id;
20502050
}
20512051
{
2052-
<EXCLUDE> <LPAREN> { s = span(); }
2052+
( <EXCLUDE> | <EXCEPT> ) <LPAREN> { s = span(); }
20532053
id = CompoundIdentifier() {
20542054
list.add(id);
20552055
}

core/src/main/java/org/apache/calcite/runtime/CalciteResource.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -807,13 +807,13 @@ ExInst<CalciteException> illegalArgumentForTableFunctionCall(String a0,
807807
@BaseMessage("SELECT * requires a FROM clause")
808808
ExInst<SqlValidatorException> selectStarRequiresFrom();
809809

810-
@BaseMessage("EXCLUDE clause must follow a STAR expression")
810+
@BaseMessage("EXCLUDE/EXCEPT clause must follow a STAR expression")
811811
ExInst<CalciteException> selectExcludeRequiresStar();
812812

813-
@BaseMessage("SELECT * EXCLUDE list contains unknown column(s): {0}")
813+
@BaseMessage("SELECT * EXCLUDE/EXCEPT list contains unknown column(s): {0}")
814814
ExInst<SqlValidatorException> selectStarExcludeListContainsUnknownColumns(String columns);
815815

816-
@BaseMessage("SELECT * EXCLUDE list cannot exclude all columns")
816+
@BaseMessage("SELECT * EXCLUDE/EXCEPT list cannot exclude all columns")
817817
ExInst<SqlValidatorException> selectStarExcludeCannotExcludeAllColumns();
818818

819819
@BaseMessage("Group function ''{0}'' can only appear in GROUP BY clause")

core/src/main/resources/org/apache/calcite/runtime/CalciteResource.properties

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,9 @@ CannotStreamResultsForNonStreamingInputs=Cannot stream results of a query with n
266266
MinusNotAllowed=MINUS is not allowed under the current SQL conformance level
267267
SelectMissingFrom=SELECT must have a FROM clause
268268
SelectStarRequiresFrom=SELECT * requires a FROM clause
269-
SelectExcludeRequiresStar=EXCLUDE clause must follow a STAR expression
270-
SelectStarExcludeListContainsUnknownColumns=SELECT * EXCLUDE list contains unknown column(s): {0}
271-
SelectStarExcludeCannotExcludeAllColumns=SELECT * EXCLUDE list cannot exclude all columns
269+
SelectExcludeRequiresStar=EXCLUDE/EXCEPT clause must follow a STAR expression
270+
SelectStarExcludeListContainsUnknownColumns=SELECT * EXCLUDE/EXCEPT list contains unknown column(s): {0}
271+
SelectStarExcludeCannotExcludeAllColumns=SELECT * EXCLUDE/EXCEPT list cannot exclude all columns
272272
GroupFunctionMustAppearInGroupByClause=Group function ''{0}'' can only appear in GROUP BY clause
273273
AuxiliaryWithoutMatchingGroupCall=Call to auxiliary group function ''{0}'' must have matching call to group function ''{1}'' in GROUP BY clause
274274
PivotAggMalformed=Measure expression in PIVOT must use aggregate function

site/_docs/reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ starWithExclude:
246246

247247
Note:
248248

249-
* `SELECT * EXCLUDE (...)` is recognized only when the Babel parser is enabled. It sets the generated parser configuration flag `includeStarExclude` to `true` (the standard parser leaves that flag `false`), which allows a `STAR` token followed by `EXCLUDE` and a parenthesized identifier list to be parsed into a `SqlStarExclude` node and ensures validators respect the exclusion list when expanding the projection. Reusing the same parser configuration elsewhere enables the same syntax for other components that need it.
249+
* `SELECT * EXCLUDE (...)` is recognized only when the Babel parser is enabled. It sets the generated parser configuration flag `includeStarExclude` to `true` (the standard parser leaves that flag `false`), which allows a `STAR` token followed by `EXCLUDE` (or the alias `EXCEPT`) and a parenthesized identifier list to be parsed into a `SqlStarExclude` node and ensures validators respect the exclusion list when expanding the projection. Reusing the same parser configuration elsewhere enables the same syntax for other components that need it.
250250

251251
projectItem:
252252
expression [ [ AS ] columnAlias ]

0 commit comments

Comments
 (0)