Skip to content

Commit 99a8d21

Browse files
committed
feat(impala): add impala expression column
1 parent dc2acf9 commit 99a8d21

File tree

10 files changed

+3718
-3256
lines changed

10 files changed

+3718
-3256
lines changed

src/grammar/impala/ImpalaSqlParser.g4

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -344,18 +344,18 @@ deleteStatement
344344
;
345345

346346
delete
347-
: KW_DELETE KW_FROM? tableNamePath (KW_WHERE booleanExpression)?
347+
: KW_DELETE KW_FROM? tableNamePath (whereClause)?
348348
;
349349

350350
deleteTableRef
351351
: KW_DELETE tableNamePath (KW_AS? identifier)? KW_FROM (relation (COMMA relation)*)? (
352-
KW_WHERE booleanExpression
352+
whereClause
353353
)?
354354
;
355355

356356
updateStatement
357357
: KW_UPDATE tableNamePath KW_SET assignmentList (KW_FROM relation (COMMA relation)*)? (
358-
KW_WHERE booleanExpression
358+
whereClause
359359
)?
360360
;
361361

@@ -563,6 +563,10 @@ columnNamePath
563563
| {this.shouldMatchEmpty()}?
564564
;
565565

566+
columnName
567+
: qualifiedName
568+
;
569+
566570
tableOrViewPath
567571
: tableNamePath
568572
| viewNamePath
@@ -769,9 +773,15 @@ sortItem
769773
querySpecification
770774
: KW_SELECT setQuantifier? (KW_STRAIGHT_JOIN)? selectItem (COMMA selectItem)* (
771775
KW_FROM relation (COMMA relation)*
772-
)? (KW_WHERE where=booleanExpression)? (KW_GROUP KW_BY groupBy)? (
773-
KW_HAVING having=booleanExpression
774-
)?
776+
)? (whereClause)? (KW_GROUP KW_BY groupBy)? (havingClause)?
777+
;
778+
779+
whereClause
780+
: KW_WHERE where=booleanExpression
781+
;
782+
783+
havingClause
784+
: KW_HAVING having=booleanExpression
775785
;
776786

777787
groupBy
@@ -933,7 +943,7 @@ primaryExpression
933943
| KW_TRY_CAST LPAREN expression KW_AS type RPAREN # cast
934944
| KW_ARRAY LSQUARE (expression (COMMA expression)*)? RSQUARE # arrayConstructor
935945
| value=primaryExpression LSQUARE index=valueExpression RSQUARE # subscript
936-
| identifier # columnReference
946+
| columnName # columnReference
937947
| base=primaryExpression DOT fieldName=identifier # dereference
938948
| name=KW_CURRENT_DATE # specialDateTimeFunction
939949
| name=KW_CURRENT_TIME (LPAREN precision=INTEGER_VALUE RPAREN)? # specialDateTimeFunction
@@ -1050,11 +1060,15 @@ whenClause
10501060
;
10511061

10521062
filter
1053-
: KW_FILTER LPAREN KW_WHERE booleanExpression RPAREN
1063+
: KW_FILTER LPAREN whereClause RPAREN
1064+
;
1065+
1066+
partitionByClause
1067+
: partition+=expression (COMMA partition+=expression)*
10541068
;
10551069

10561070
over
1057-
: KW_OVER LPAREN (KW_PARTITION KW_BY partition+=expression (COMMA partition+=expression)*)? (
1071+
: KW_OVER LPAREN (KW_PARTITION KW_BY partitionByClause)? (
10581072
KW_ORDER KW_BY sortItem (COMMA sortItem)*
10591073
)? windowFrame? RPAREN
10601074
;
@@ -1093,7 +1107,7 @@ privilege
10931107
| KW_CREATE
10941108
| KW_INSERT
10951109
| KW_REFRESH
1096-
| KW_SELECT (LPAREN columnName=identifier RPAREN)?
1110+
| KW_SELECT (LPAREN name=identifier RPAREN)?
10971111
;
10981112

10991113
objectType

src/lib/impala/ImpalaSqlParser.interp

Lines changed: 5 additions & 1 deletion
Large diffs are not rendered by default.

src/lib/impala/ImpalaSqlParser.ts

Lines changed: 3457 additions & 3245 deletions
Large diffs are not rendered by default.

src/lib/impala/ImpalaSqlParserListener.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ import { TableNamePathContext } from "./ImpalaSqlParser.js";
105105
import { ViewNamePathContext } from "./ImpalaSqlParser.js";
106106
import { FunctionNamePathContext } from "./ImpalaSqlParser.js";
107107
import { ColumnNamePathContext } from "./ImpalaSqlParser.js";
108+
import { ColumnNameContext } from "./ImpalaSqlParser.js";
108109
import { TableOrViewPathContext } from "./ImpalaSqlParser.js";
109110
import { CreateCommonItemContext } from "./ImpalaSqlParser.js";
110111
import { AssignmentListContext } from "./ImpalaSqlParser.js";
@@ -148,6 +149,8 @@ import { InlineTableContext } from "./ImpalaSqlParser.js";
148149
import { SubqueryContext } from "./ImpalaSqlParser.js";
149150
import { SortItemContext } from "./ImpalaSqlParser.js";
150151
import { QuerySpecificationContext } from "./ImpalaSqlParser.js";
152+
import { WhereClauseContext } from "./ImpalaSqlParser.js";
153+
import { HavingClauseContext } from "./ImpalaSqlParser.js";
151154
import { GroupByContext } from "./ImpalaSqlParser.js";
152155
import { SingleGroupingSetContext } from "./ImpalaSqlParser.js";
153156
import { GroupingSetContext } from "./ImpalaSqlParser.js";
@@ -228,6 +231,7 @@ import { TypeParameterContext } from "./ImpalaSqlParser.js";
228231
import { BaseTypeContext } from "./ImpalaSqlParser.js";
229232
import { WhenClauseContext } from "./ImpalaSqlParser.js";
230233
import { FilterContext } from "./ImpalaSqlParser.js";
234+
import { PartitionByClauseContext } from "./ImpalaSqlParser.js";
231235
import { OverContext } from "./ImpalaSqlParser.js";
232236
import { WindowFrameContext } from "./ImpalaSqlParser.js";
233237
import { UnboundedFrameContext } from "./ImpalaSqlParser.js";
@@ -1228,6 +1232,16 @@ export class ImpalaSqlParserListener implements ParseTreeListener {
12281232
* @param ctx the parse tree
12291233
*/
12301234
exitColumnNamePath?: (ctx: ColumnNamePathContext) => void;
1235+
/**
1236+
* Enter a parse tree produced by `ImpalaSqlParser.columnName`.
1237+
* @param ctx the parse tree
1238+
*/
1239+
enterColumnName?: (ctx: ColumnNameContext) => void;
1240+
/**
1241+
* Exit a parse tree produced by `ImpalaSqlParser.columnName`.
1242+
* @param ctx the parse tree
1243+
*/
1244+
exitColumnName?: (ctx: ColumnNameContext) => void;
12311245
/**
12321246
* Enter a parse tree produced by `ImpalaSqlParser.tableOrViewPath`.
12331247
* @param ctx the parse tree
@@ -1670,6 +1684,26 @@ export class ImpalaSqlParserListener implements ParseTreeListener {
16701684
* @param ctx the parse tree
16711685
*/
16721686
exitQuerySpecification?: (ctx: QuerySpecificationContext) => void;
1687+
/**
1688+
* Enter a parse tree produced by `ImpalaSqlParser.whereClause`.
1689+
* @param ctx the parse tree
1690+
*/
1691+
enterWhereClause?: (ctx: WhereClauseContext) => void;
1692+
/**
1693+
* Exit a parse tree produced by `ImpalaSqlParser.whereClause`.
1694+
* @param ctx the parse tree
1695+
*/
1696+
exitWhereClause?: (ctx: WhereClauseContext) => void;
1697+
/**
1698+
* Enter a parse tree produced by `ImpalaSqlParser.havingClause`.
1699+
* @param ctx the parse tree
1700+
*/
1701+
enterHavingClause?: (ctx: HavingClauseContext) => void;
1702+
/**
1703+
* Exit a parse tree produced by `ImpalaSqlParser.havingClause`.
1704+
* @param ctx the parse tree
1705+
*/
1706+
exitHavingClause?: (ctx: HavingClauseContext) => void;
16731707
/**
16741708
* Enter a parse tree produced by `ImpalaSqlParser.groupBy`.
16751709
* @param ctx the parse tree
@@ -2574,6 +2608,16 @@ export class ImpalaSqlParserListener implements ParseTreeListener {
25742608
* @param ctx the parse tree
25752609
*/
25762610
exitFilter?: (ctx: FilterContext) => void;
2611+
/**
2612+
* Enter a parse tree produced by `ImpalaSqlParser.partitionByClause`.
2613+
* @param ctx the parse tree
2614+
*/
2615+
enterPartitionByClause?: (ctx: PartitionByClauseContext) => void;
2616+
/**
2617+
* Exit a parse tree produced by `ImpalaSqlParser.partitionByClause`.
2618+
* @param ctx the parse tree
2619+
*/
2620+
exitPartitionByClause?: (ctx: PartitionByClauseContext) => void;
25772621
/**
25782622
* Enter a parse tree produced by `ImpalaSqlParser.over`.
25792623
* @param ctx the parse tree

src/lib/impala/ImpalaSqlParserVisitor.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ import { TableNamePathContext } from "./ImpalaSqlParser.js";
105105
import { ViewNamePathContext } from "./ImpalaSqlParser.js";
106106
import { FunctionNamePathContext } from "./ImpalaSqlParser.js";
107107
import { ColumnNamePathContext } from "./ImpalaSqlParser.js";
108+
import { ColumnNameContext } from "./ImpalaSqlParser.js";
108109
import { TableOrViewPathContext } from "./ImpalaSqlParser.js";
109110
import { CreateCommonItemContext } from "./ImpalaSqlParser.js";
110111
import { AssignmentListContext } from "./ImpalaSqlParser.js";
@@ -148,6 +149,8 @@ import { InlineTableContext } from "./ImpalaSqlParser.js";
148149
import { SubqueryContext } from "./ImpalaSqlParser.js";
149150
import { SortItemContext } from "./ImpalaSqlParser.js";
150151
import { QuerySpecificationContext } from "./ImpalaSqlParser.js";
152+
import { WhereClauseContext } from "./ImpalaSqlParser.js";
153+
import { HavingClauseContext } from "./ImpalaSqlParser.js";
151154
import { GroupByContext } from "./ImpalaSqlParser.js";
152155
import { SingleGroupingSetContext } from "./ImpalaSqlParser.js";
153156
import { GroupingSetContext } from "./ImpalaSqlParser.js";
@@ -228,6 +231,7 @@ import { TypeParameterContext } from "./ImpalaSqlParser.js";
228231
import { BaseTypeContext } from "./ImpalaSqlParser.js";
229232
import { WhenClauseContext } from "./ImpalaSqlParser.js";
230233
import { FilterContext } from "./ImpalaSqlParser.js";
234+
import { PartitionByClauseContext } from "./ImpalaSqlParser.js";
231235
import { OverContext } from "./ImpalaSqlParser.js";
232236
import { WindowFrameContext } from "./ImpalaSqlParser.js";
233237
import { UnboundedFrameContext } from "./ImpalaSqlParser.js";
@@ -843,6 +847,12 @@ export class ImpalaSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Res
843847
* @return the visitor result
844848
*/
845849
visitColumnNamePath?: (ctx: ColumnNamePathContext) => Result;
850+
/**
851+
* Visit a parse tree produced by `ImpalaSqlParser.columnName`.
852+
* @param ctx the parse tree
853+
* @return the visitor result
854+
*/
855+
visitColumnName?: (ctx: ColumnNameContext) => Result;
846856
/**
847857
* Visit a parse tree produced by `ImpalaSqlParser.tableOrViewPath`.
848858
* @param ctx the parse tree
@@ -1107,6 +1117,18 @@ export class ImpalaSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Res
11071117
* @return the visitor result
11081118
*/
11091119
visitQuerySpecification?: (ctx: QuerySpecificationContext) => Result;
1120+
/**
1121+
* Visit a parse tree produced by `ImpalaSqlParser.whereClause`.
1122+
* @param ctx the parse tree
1123+
* @return the visitor result
1124+
*/
1125+
visitWhereClause?: (ctx: WhereClauseContext) => Result;
1126+
/**
1127+
* Visit a parse tree produced by `ImpalaSqlParser.havingClause`.
1128+
* @param ctx the parse tree
1129+
* @return the visitor result
1130+
*/
1131+
visitHavingClause?: (ctx: HavingClauseContext) => Result;
11101132
/**
11111133
* Visit a parse tree produced by `ImpalaSqlParser.groupBy`.
11121134
* @param ctx the parse tree
@@ -1639,6 +1661,12 @@ export class ImpalaSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Res
16391661
* @return the visitor result
16401662
*/
16411663
visitFilter?: (ctx: FilterContext) => Result;
1664+
/**
1665+
* Visit a parse tree produced by `ImpalaSqlParser.partitionByClause`.
1666+
* @param ctx the parse tree
1667+
* @return the visitor result
1668+
*/
1669+
visitPartitionByClause?: (ctx: PartitionByClauseContext) => Result;
16421670
/**
16431671
* Visit a parse tree produced by `ImpalaSqlParser.over`.
16441672
* @param ctx the parse tree

src/parser/impala/ImpalaErrorListener.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class ImpalaErrorListener extends ParseErrorListener {
1616
[ImpalaSqlParser.RULE_viewNameCreate, 'view'],
1717
[ImpalaSqlParser.RULE_functionNamePath, 'function'],
1818
[ImpalaSqlParser.RULE_functionNameCreate, 'function'],
19+
[ImpalaSqlParser.RULE_columnName, 'column'],
1920
[ImpalaSqlParser.RULE_columnNamePath, 'column'],
2021
[ImpalaSqlParser.RULE_columnNamePathCreate, 'column'],
2122
]);
@@ -48,6 +49,7 @@ export class ImpalaErrorListener extends ParseErrorListener {
4849
case ImpalaSqlParser.RULE_tableNamePath:
4950
case ImpalaSqlParser.RULE_functionNamePath:
5051
case ImpalaSqlParser.RULE_viewNamePath:
52+
case ImpalaSqlParser.RULE_columnName:
5153
case ImpalaSqlParser.RULE_columnNamePath: {
5254
result.push(`{existing}${name}`);
5355
break;

src/parser/impala/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class ImpalaSQL extends BasicSQL<ImpalaSqlLexer, ProgramContext, ImpalaSq
3232
ImpalaSqlParser.RULE_viewNamePath,
3333
ImpalaSqlParser.RULE_databaseNamePath,
3434
ImpalaSqlParser.RULE_columnNamePath,
35+
ImpalaSqlParser.RULE_columnName,
3536
]);
3637

3738
protected get splitListener() {
@@ -103,6 +104,18 @@ export class ImpalaSQL extends BasicSQL<ImpalaSqlLexer, ProgramContext, ImpalaSq
103104
case ImpalaSqlParser.RULE_columnNamePath: {
104105
syntaxContextType = EntityContextType.COLUMN;
105106
}
107+
case ImpalaSqlParser.RULE_columnName: {
108+
if (
109+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_columnItem) ||
110+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_havingClause) ||
111+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_whereClause) ||
112+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_whenClause) ||
113+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_partitionByClause) ||
114+
candidateRule.ruleList.includes(ImpalaSqlParser.RULE_relation)
115+
) {
116+
syntaxContextType = EntityContextType.COLUMN;
117+
}
118+
}
106119
default:
107120
break;
108121
}

test/parser/impala/errorListener.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const sql2 = `SELECT * FROM `;
66
const sql3 = `DROP VIEW IF EXIsST aaa aaa`;
77
const sql4 = `SELECT * froma aaa`;
88
const sql5 = `CREATE VIEW `;
9+
const sql6 = 'SELECT * FROM t1 LEFT OUTER JOIN t2 ON t1.int_col < ';
910

1011
describe('ImpalaSQL validate invalid sql and test msg', () => {
1112
const impala = new ImpalaSQL();
@@ -55,6 +56,14 @@ describe('ImpalaSQL validate invalid sql and test msg', () => {
5556
);
5657
});
5758

59+
test('validate unComplete sql6', () => {
60+
const errors = impala.validate(sql6);
61+
expect(errors.length).toBe(1);
62+
expect(errors[0].message).toBe(
63+
`'<' is not valid at this position, expecting an existing column or a keyword`
64+
);
65+
});
66+
5867
test('validate random text cn', () => {
5968
impala.locale = 'zh_CN';
6069
const errors = impala.validate(randomText);
@@ -88,4 +97,10 @@ describe('ImpalaSQL validate invalid sql and test msg', () => {
8897
expect(errors.length).toBe(1);
8998
expect(errors[0].message).toBe(`'froma' 在此位置无效,期望一个关键字`);
9099
});
100+
101+
test('validate unComplete sql6', () => {
102+
const errors = impala.validate(sql6);
103+
expect(errors.length).toBe(1);
104+
expect(errors[0].message).toBe(`'<' 在此位置无效,期望一个存在的column或者一个关键字`);
105+
});
91106
});

test/parser/impala/suggestion/fixtures/suggestionWithEntity.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@ INSERT INTO insert_tb SELECT id, FROM from_tb;
99
CREATE TABLE sorted_census_data AS SELECT FROM unsorted_census_data;
1010

1111
CREATE TABLE sorted_census_data AS SELECT id, FROM unsorted_census_data;
12+
13+
SELECT t1.c1, t2.c2 FROM t1, t2 WHERE t1.id = t2.id AND t1.type_flag = t2.type_flag AND t1.c1 > 100;
14+
15+
SELECT * FROM t1 LEFT OUTER JOIN t2 ON t1.int_col < t2.int_col;
16+
17+
SELECT user_id AS "Top 10 Visitors", SUM(page_views) FROM web_stats GROUP BY page_views, user_id having times_purchased >= 100 ORDER BY SUM(page_views) DESC LIMIT 10;
18+
19+
UPDATE my_table SET col1 = CASE WHEN col2 > 10 THEN 'High' WHEN col2 > 5 THEN 'Medium' ELSE 'Low' END WHERE col3 = 'value';
20+
21+
create table million_rows_one_range (id string primary key, s string) partition by hash(id) partitions 50, range (partition 'a' <= values < '{') stored as kudu;

0 commit comments

Comments
 (0)