Skip to content

Commit 7fb4c56

Browse files
committed
feat(hive): add hive expression column
1 parent 7b95431 commit 7fb4c56

10 files changed

+6491
-5644
lines changed

src/grammar/hive/HiveSqlParser.g4

+12-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License. You may obtain a copy of the
66
License at
7-
7+
88
http://www.apache.org/licenses/LICENSE-2.0
9-
9+
1010
Unless required by applicable law or agreed to in writing, software distributed under the License
1111
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1212
implied. See the License for the specific language governing permissions and limitations under the
@@ -758,6 +758,10 @@ columnName
758758
| {this.shouldMatchEmpty()}?
759759
;
760760

761+
columnNamePath
762+
: poolPath
763+
;
764+
761765
columnNameCreate
762766
: id_
763767
;
@@ -1437,7 +1441,7 @@ subQuerySource
14371441
Rules for parsing PTF clauses
14381442
*/
14391443
partitioningSpec
1440-
: KW_PARTITION KW_BY expressions orderByClause?
1444+
: partitionByClause orderByClause?
14411445
| orderByClause
14421446
| distributeByClause sortByClause?
14431447
| sortByClause
@@ -1613,6 +1617,10 @@ orderByClause
16131617
: KW_ORDER KW_BY columnRefOrder (COMMA columnRefOrder)*
16141618
;
16151619

1620+
partitionByClause
1621+
: KW_PARTITION KW_BY expressions
1622+
;
1623+
16161624
clusterByClause
16171625
: KW_CLUSTER KW_BY expressions
16181626
;
@@ -1714,7 +1722,7 @@ constant
17141722
| KW_FALSE
17151723
| KW_NULL
17161724
| p=QUESTION
1717-
| Identifier
1725+
| columnNamePath
17181726
;
17191727

17201728
intervalValue

src/lib/hive/HiveSqlParser.interp

+3-1
Large diffs are not rendered by default.

src/lib/hive/HiveSqlParser.ts

+6,227-5,637
Large diffs are not rendered by default.

src/lib/hive/HiveSqlParserListener.ts

+22
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ import { ColumnNameTypeOrConstraintListContext } from "./HiveSqlParser.js";
137137
import { ColumnNameColonTypeListContext } from "./HiveSqlParser.js";
138138
import { ColumnNameListContext } from "./HiveSqlParser.js";
139139
import { ColumnNameContext } from "./HiveSqlParser.js";
140+
import { ColumnNamePathContext } from "./HiveSqlParser.js";
140141
import { ColumnNameCreateContext } from "./HiveSqlParser.js";
141142
import { ExtColumnNameContext } from "./HiveSqlParser.js";
142143
import { ColumnNameOrderListContext } from "./HiveSqlParser.js";
@@ -282,6 +283,7 @@ import { ExpressionsContext } from "./HiveSqlParser.js";
282283
import { ExpressionsInParenthesisContext } from "./HiveSqlParser.js";
283284
import { ExpressionsNotInParenthesisContext } from "./HiveSqlParser.js";
284285
import { OrderByClauseContext } from "./HiveSqlParser.js";
286+
import { PartitionByClauseContext } from "./HiveSqlParser.js";
285287
import { ClusterByClauseContext } from "./HiveSqlParser.js";
286288
import { DistributeByClauseContext } from "./HiveSqlParser.js";
287289
import { SortByClauseContext } from "./HiveSqlParser.js";
@@ -1653,6 +1655,16 @@ export class HiveSqlParserListener implements ParseTreeListener {
16531655
* @param ctx the parse tree
16541656
*/
16551657
exitColumnName?: (ctx: ColumnNameContext) => void;
1658+
/**
1659+
* Enter a parse tree produced by `HiveSqlParser.columnNamePath`.
1660+
* @param ctx the parse tree
1661+
*/
1662+
enterColumnNamePath?: (ctx: ColumnNamePathContext) => void;
1663+
/**
1664+
* Exit a parse tree produced by `HiveSqlParser.columnNamePath`.
1665+
* @param ctx the parse tree
1666+
*/
1667+
exitColumnNamePath?: (ctx: ColumnNamePathContext) => void;
16561668
/**
16571669
* Enter a parse tree produced by `HiveSqlParser.columnNameCreate`.
16581670
* @param ctx the parse tree
@@ -3111,6 +3123,16 @@ export class HiveSqlParserListener implements ParseTreeListener {
31113123
* @param ctx the parse tree
31123124
*/
31133125
exitOrderByClause?: (ctx: OrderByClauseContext) => void;
3126+
/**
3127+
* Enter a parse tree produced by `HiveSqlParser.partitionByClause`.
3128+
* @param ctx the parse tree
3129+
*/
3130+
enterPartitionByClause?: (ctx: PartitionByClauseContext) => void;
3131+
/**
3132+
* Exit a parse tree produced by `HiveSqlParser.partitionByClause`.
3133+
* @param ctx the parse tree
3134+
*/
3135+
exitPartitionByClause?: (ctx: PartitionByClauseContext) => void;
31143136
/**
31153137
* Enter a parse tree produced by `HiveSqlParser.clusterByClause`.
31163138
* @param ctx the parse tree

src/lib/hive/HiveSqlParserVisitor.ts

+14
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ import { ColumnNameTypeOrConstraintListContext } from "./HiveSqlParser.js";
137137
import { ColumnNameColonTypeListContext } from "./HiveSqlParser.js";
138138
import { ColumnNameListContext } from "./HiveSqlParser.js";
139139
import { ColumnNameContext } from "./HiveSqlParser.js";
140+
import { ColumnNamePathContext } from "./HiveSqlParser.js";
140141
import { ColumnNameCreateContext } from "./HiveSqlParser.js";
141142
import { ExtColumnNameContext } from "./HiveSqlParser.js";
142143
import { ColumnNameOrderListContext } from "./HiveSqlParser.js";
@@ -282,6 +283,7 @@ import { ExpressionsContext } from "./HiveSqlParser.js";
282283
import { ExpressionsInParenthesisContext } from "./HiveSqlParser.js";
283284
import { ExpressionsNotInParenthesisContext } from "./HiveSqlParser.js";
284285
import { OrderByClauseContext } from "./HiveSqlParser.js";
286+
import { PartitionByClauseContext } from "./HiveSqlParser.js";
285287
import { ClusterByClauseContext } from "./HiveSqlParser.js";
286288
import { DistributeByClauseContext } from "./HiveSqlParser.js";
287289
import { SortByClauseContext } from "./HiveSqlParser.js";
@@ -1140,6 +1142,12 @@ export class HiveSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Resul
11401142
* @return the visitor result
11411143
*/
11421144
visitColumnName?: (ctx: ColumnNameContext) => Result;
1145+
/**
1146+
* Visit a parse tree produced by `HiveSqlParser.columnNamePath`.
1147+
* @param ctx the parse tree
1148+
* @return the visitor result
1149+
*/
1150+
visitColumnNamePath?: (ctx: ColumnNamePathContext) => Result;
11431151
/**
11441152
* Visit a parse tree produced by `HiveSqlParser.columnNameCreate`.
11451153
* @param ctx the parse tree
@@ -2014,6 +2022,12 @@ export class HiveSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Resul
20142022
* @return the visitor result
20152023
*/
20162024
visitOrderByClause?: (ctx: OrderByClauseContext) => Result;
2025+
/**
2026+
* Visit a parse tree produced by `HiveSqlParser.partitionByClause`.
2027+
* @param ctx the parse tree
2028+
* @return the visitor result
2029+
*/
2030+
visitPartitionByClause?: (ctx: PartitionByClauseContext) => Result;
20172031
/**
20182032
* Visit a parse tree produced by `HiveSqlParser.clusterByClause`.
20192033
* @param ctx the parse tree

src/parser/hive/hiveErrorListener.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class HiveErrorListener extends ParseErrorListener {
1919
[HiveSqlParser.RULE_functionNameCreate, 'function'],
2020
[HiveSqlParser.RULE_columnName, 'column'],
2121
[HiveSqlParser.RULE_columnNameCreate, 'column'],
22+
[HiveSqlParser.RULE_columnNamePath, 'column'],
2223
]);
2324

2425
constructor(errorListener: ErrorListener, preferredRules: Set<number>, locale: LOCALE_TYPE) {
@@ -50,7 +51,8 @@ export class HiveErrorListener extends ParseErrorListener {
5051
case HiveSqlParser.RULE_viewName:
5152
case HiveSqlParser.RULE_functionNameForDDL:
5253
case HiveSqlParser.RULE_functionNameForInvoke:
53-
case HiveSqlParser.RULE_columnName: {
54+
case HiveSqlParser.RULE_columnName:
55+
case HiveSqlParser.RULE_columnNamePath: {
5456
result.push(`{existing}${name}`);
5557
break;
5658
}

src/parser/hive/index.ts

+17
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class HiveSQL extends BasicSQL<HiveSqlLexer, ProgramContext, HiveSqlParse
3333
HiveSqlParser.RULE_functionNameForInvoke, // function name
3434
HiveSqlParser.RULE_functionNameCreate, // function name that will be created
3535
HiveSqlParser.RULE_columnName,
36+
HiveSqlParser.RULE_columnNamePath,
3637
HiveSqlParser.RULE_columnNameCreate,
3738
]);
3839

@@ -107,6 +108,22 @@ export class HiveSQL extends BasicSQL<HiveSqlLexer, ProgramContext, HiveSqlParse
107108
syntaxContextType = EntityContextType.COLUMN_CREATE;
108109
break;
109110
}
111+
case HiveSqlParser.RULE_columnNamePath: {
112+
if (
113+
candidateRule.ruleList.includes(HiveSqlParser.RULE_orderByClause) ||
114+
candidateRule.ruleList.includes(HiveSqlParser.RULE_havingClause) ||
115+
candidateRule.ruleList.includes(HiveSqlParser.RULE_groupByClause) ||
116+
candidateRule.ruleList.includes(HiveSqlParser.RULE_sortByClause) ||
117+
candidateRule.ruleList.includes(HiveSqlParser.RULE_whereClause) ||
118+
candidateRule.ruleList.includes(HiveSqlParser.RULE_qualifyClause) ||
119+
candidateRule.ruleList.includes(HiveSqlParser.RULE_clusterByClause) ||
120+
candidateRule.ruleList.includes(HiveSqlParser.RULE_distributeByClause) ||
121+
candidateRule.ruleList.includes(HiveSqlParser.RULE_selectClause)
122+
) {
123+
syntaxContextType = EntityContextType.COLUMN;
124+
}
125+
break;
126+
}
110127
default:
111128
break;
112129
}

test/parser/hive/errorListener.test.ts

+23
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 TABLE `;
9+
const sql6 = `SELECT col1 FROM t1 GROUP BY col1 HAVING SUM(col2 `;
910

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

59+
test('validate unComplete sql6', () => {
60+
const errors = hive.validate(sql6);
61+
expect(errors.length).toBe(1);
62+
expect(errors[0].message).toBe(
63+
`Statement is incomplete, expecting an existing function or an existing column or a keyword`
64+
);
65+
});
66+
5867
test('validate random text cn', () => {
5968
hive.locale = 'zh_CN';
6069
const errors = hive.validate(randomText);
@@ -88,4 +97,18 @@ describe('HiveSQL 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 sql5', () => {
102+
const errors = hive.validate(sql5);
103+
expect(errors.length).toBe(1);
104+
expect(errors[0].message).toBe(`语句不完整,期望一个新的table或者一个关键字`);
105+
});
106+
107+
test('validate unComplete sql6 cn', () => {
108+
const errors = hive.validate(sql6);
109+
expect(errors.length).toBe(1);
110+
expect(errors[0].message).toBe(
111+
`语句不完整,期望一个存在的function或者一个存在的column或者一个关键字`
112+
);
113+
});
91114
});

test/parser/hive/suggestion/fixtures/syntaxSuggestion.sql

+17-1
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,20 @@ FROM table_name_1 SELECT col1, col2;
3838

3939
FROM a JOIN b ON (a.id = b.id AND a.department = b.department) SELECT a.*;
4040

41-
FROM page_view_stg INSERT;
41+
FROM page_view_stg INSERT;
42+
43+
SELECT key FROM (SELECT key FROM src ORDER BY sum(a,b) LIMIT 10)subq1;
44+
45+
SELECT col1 FROM t1 GROUP BY col1 HAVING SUM(col2) > 10;
46+
47+
SELECT col1 FROM (SELECT col1, SUM(col2) AS col2sum FROM t1 GROUP BY col1 > 20) t2 WHERE t2.col2sum > 10;
48+
49+
SELECT col1, col2 FROM t1 DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC;
50+
51+
SELECT id, RANK() OVER (PARTITION BY customer_id ORDER BY sale_date) AS rank FROM sales QUALIFY rank = 1;
52+
53+
SELECT id, customer_id, amount FROM sales CLUSTER BY customer_id;
54+
55+
SELECT sum(t3.col), col2 FROM t1 DISTRIBUTE BY col1 SORT BY col1 ASC, col2 DESC;
56+
57+
SELECT a, COUNT(b) OVER (PARTITION BY c, d) FROM T;

0 commit comments

Comments
 (0)