dt-sql-parser 4.0.2 → 4.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/lib/flink/FlinkSqlLexer.js +1 -2
- package/dist/lib/flink/FlinkSqlParser.d.ts +175 -174
- package/dist/lib/flink/FlinkSqlParser.js +2315 -2388
- package/dist/lib/flink/FlinkSqlParserListener.d.ts +5 -16
- package/dist/lib/flink/FlinkSqlParserVisitor.d.ts +3 -10
- package/dist/lib/hive/HiveSqlLexer.js +1 -2
- package/dist/lib/hive/HiveSqlParser.d.ts +3 -1
- package/dist/lib/hive/HiveSqlParser.js +8 -9
- package/dist/lib/impala/ImpalaSqlLexer.js +1 -2
- package/dist/lib/impala/ImpalaSqlParser.d.ts +123 -107
- package/dist/lib/impala/ImpalaSqlParser.js +3223 -3155
- package/dist/lib/impala/ImpalaSqlParserListener.d.ts +22 -0
- package/dist/lib/impala/ImpalaSqlParserVisitor.d.ts +14 -0
- package/dist/lib/mysql/MySqlLexer.js +1 -2
- package/dist/lib/mysql/MySqlParser.d.ts +469 -422
- package/dist/lib/mysql/MySqlParser.js +11460 -10509
- package/dist/lib/mysql/MySqlParserListener.d.ts +33 -11
- package/dist/lib/mysql/MySqlParserVisitor.d.ts +21 -7
- package/dist/lib/postgresql/PostgreSqlLexer.js +1 -2
- package/dist/lib/postgresql/PostgreSqlParser.d.ts +2025 -6265
- package/dist/lib/postgresql/PostgreSqlParser.js +60092 -88368
- package/dist/lib/postgresql/PostgreSqlParserListener.d.ts +1688 -6083
- package/dist/lib/postgresql/PostgreSqlParserVisitor.d.ts +712 -3511
- package/dist/lib/spark/SparkSqlLexer.js +1 -2
- package/dist/lib/spark/SparkSqlParser.d.ts +16 -13
- package/dist/lib/spark/SparkSqlParser.js +50 -51
- package/dist/lib/spark/SparkSqlParserListener.d.ts +10 -10
- package/dist/lib/spark/SparkSqlParserVisitor.d.ts +6 -6
- package/dist/lib/trino/TrinoSqlLexer.d.ts +323 -260
- package/dist/lib/trino/TrinoSqlLexer.js +1610 -1264
- package/dist/lib/trino/TrinoSqlListener.d.ts +1311 -200
- package/dist/lib/trino/TrinoSqlParser.d.ts +1908 -562
- package/dist/lib/trino/TrinoSqlParser.js +22629 -13412
- package/dist/lib/trino/TrinoSqlVisitor.d.ts +761 -69
- package/dist/locale/locale.d.ts +41 -0
- package/dist/locale/locale.js +43 -0
- package/dist/parser/common/basicSQL.d.ts +9 -4
- package/dist/parser/common/basicSQL.js +64 -21
- package/dist/parser/common/entityCollector.d.ts +60 -12
- package/dist/parser/common/entityCollector.js +141 -17
- package/dist/parser/common/parseErrorListener.d.ts +6 -3
- package/dist/parser/common/parseErrorListener.js +83 -2
- package/dist/parser/common/textAndWord.d.ts +6 -9
- package/dist/parser/common/textAndWord.js +9 -20
- package/dist/parser/common/transform.d.ts +8 -0
- package/dist/parser/common/transform.js +11 -0
- package/dist/parser/common/types.d.ts +1 -0
- package/dist/parser/flink/flinkEntityCollector.js +40 -6
- package/dist/parser/flink/flinkErrorListener.d.ts +9 -0
- package/dist/parser/flink/flinkErrorListener.js +67 -0
- package/dist/parser/flink/index.d.ts +4 -1
- package/dist/parser/flink/index.js +16 -12
- package/dist/parser/hive/hiveEntityCollector.js +40 -6
- package/dist/parser/hive/hiveErrorListener.d.ts +9 -0
- package/dist/parser/hive/hiveErrorListener.js +65 -0
- package/dist/parser/hive/index.d.ts +4 -1
- package/dist/parser/hive/index.js +16 -12
- package/dist/parser/impala/ImpalaErrorListener.d.ts +9 -0
- package/dist/parser/impala/ImpalaErrorListener.js +63 -0
- package/dist/parser/impala/impalaEntityCollector.js +51 -6
- package/dist/parser/impala/index.d.ts +4 -1
- package/dist/parser/impala/index.js +7 -3
- package/dist/parser/mysql/index.d.ts +4 -1
- package/dist/parser/mysql/index.js +7 -3
- package/dist/parser/mysql/mysqlEntityCollector.d.ts +3 -1
- package/dist/parser/mysql/mysqlEntityCollector.js +40 -5
- package/dist/parser/mysql/mysqlErrorListener.d.ts +9 -0
- package/dist/parser/mysql/mysqlErrorListener.js +63 -0
- package/dist/parser/postgresql/index.d.ts +4 -1
- package/dist/parser/postgresql/index.js +20 -16
- package/dist/parser/postgresql/postgreEntityCollector.d.ts +5 -1
- package/dist/parser/postgresql/postgreEntityCollector.js +44 -4
- package/dist/parser/postgresql/postgreErrorListener.d.ts +9 -0
- package/dist/parser/postgresql/postgreErrorListener.js +71 -0
- package/dist/parser/spark/index.d.ts +4 -1
- package/dist/parser/spark/index.js +7 -3
- package/dist/parser/spark/sparkEntityCollector.d.ts +1 -1
- package/dist/parser/spark/sparkEntityCollector.js +43 -6
- package/dist/parser/spark/sparkErrorListener.d.ts +9 -0
- package/dist/parser/spark/sparkErrorListener.js +63 -0
- package/dist/parser/trino/index.d.ts +4 -1
- package/dist/parser/trino/index.js +26 -13
- package/dist/parser/trino/trinoEntityCollector.d.ts +6 -4
- package/dist/parser/trino/trinoEntityCollector.js +44 -9
- package/dist/parser/trino/trinoErrorListener.d.ts +9 -0
- package/dist/parser/trino/trinoErrorListener.js +65 -0
- package/package.json +35 -11
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
declare const i18n: {
|
|
2
|
+
zh_CN: {
|
|
3
|
+
stmtInComplete: string;
|
|
4
|
+
noValidPosition: string;
|
|
5
|
+
expecting: string;
|
|
6
|
+
unfinishedMultilineComment: string;
|
|
7
|
+
unfinishedDoubleQuoted: string;
|
|
8
|
+
unfinishedSingleQuoted: string;
|
|
9
|
+
unfinishedTickQuoted: string;
|
|
10
|
+
noValidInput: string;
|
|
11
|
+
newObj: string;
|
|
12
|
+
existingObj: string;
|
|
13
|
+
new: string;
|
|
14
|
+
existing: string;
|
|
15
|
+
orKeyword: string;
|
|
16
|
+
keyword: string;
|
|
17
|
+
missing: string;
|
|
18
|
+
at: string;
|
|
19
|
+
or: string;
|
|
20
|
+
};
|
|
21
|
+
en_US: {
|
|
22
|
+
stmtInComplete: string;
|
|
23
|
+
noValidPosition: string;
|
|
24
|
+
expecting: string;
|
|
25
|
+
unfinishedMultilineComment: string;
|
|
26
|
+
unfinishedDoubleQuoted: string;
|
|
27
|
+
unfinishedSingleQuoted: string;
|
|
28
|
+
unfinishedTickQuoted: string;
|
|
29
|
+
noValidInput: string;
|
|
30
|
+
newObj: string;
|
|
31
|
+
existingObj: string;
|
|
32
|
+
new: string;
|
|
33
|
+
existing: string;
|
|
34
|
+
orKeyword: string;
|
|
35
|
+
keyword: string;
|
|
36
|
+
missing: string;
|
|
37
|
+
at: string;
|
|
38
|
+
or: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export { i18n };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const zh_CN = {
|
|
2
|
+
stmtInComplete: '语句不完整',
|
|
3
|
+
noValidPosition: '在此位置无效',
|
|
4
|
+
expecting: ',期望',
|
|
5
|
+
unfinishedMultilineComment: '未完成的多行注释',
|
|
6
|
+
unfinishedDoubleQuoted: '未完成的双引号字符串字变量',
|
|
7
|
+
unfinishedSingleQuoted: '未完成的单引号字符串字变量',
|
|
8
|
+
unfinishedTickQuoted: '未完成的反引号引用字符串字变量',
|
|
9
|
+
noValidInput: '没有有效的输入',
|
|
10
|
+
newObj: '一个新的对象',
|
|
11
|
+
existingObj: '一个存在的对象',
|
|
12
|
+
new: '一个新的',
|
|
13
|
+
existing: '一个存在的',
|
|
14
|
+
orKeyword: '或者一个关键字',
|
|
15
|
+
keyword: '一个关键字',
|
|
16
|
+
missing: '缺少',
|
|
17
|
+
at: '在',
|
|
18
|
+
or: '或者',
|
|
19
|
+
};
|
|
20
|
+
const en_US = {
|
|
21
|
+
stmtInComplete: 'Statement is incomplete',
|
|
22
|
+
noValidPosition: 'is not valid at this position',
|
|
23
|
+
expecting: ', expecting ',
|
|
24
|
+
unfinishedMultilineComment: 'Unfinished multiline comment',
|
|
25
|
+
unfinishedDoubleQuoted: 'Unfinished double quoted string literal',
|
|
26
|
+
unfinishedSingleQuoted: 'Unfinished single quoted string literal',
|
|
27
|
+
unfinishedTickQuoted: 'Unfinished back tick quoted string literal',
|
|
28
|
+
noValidInput: 'is no valid input at all',
|
|
29
|
+
newObj: 'a new object',
|
|
30
|
+
existingObj: 'an existing object',
|
|
31
|
+
new: 'a new ',
|
|
32
|
+
existing: 'an existing ',
|
|
33
|
+
orKeyword: ' or a keyword',
|
|
34
|
+
keyword: 'a keyword',
|
|
35
|
+
missing: 'missing ',
|
|
36
|
+
at: ' at ',
|
|
37
|
+
or: ' or ',
|
|
38
|
+
};
|
|
39
|
+
const i18n = {
|
|
40
|
+
zh_CN,
|
|
41
|
+
en_US,
|
|
42
|
+
};
|
|
43
|
+
export { i18n };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Lexer, Token, CommonTokenStream, CharStream, ParserRuleContext, ParseTreeListener } from 'antlr4ng';
|
|
1
|
+
import { Lexer, Token, CommonTokenStream, CharStream, ParserRuleContext, ParseTreeListener, ANTLRErrorListener } from 'antlr4ng';
|
|
2
2
|
import { CandidatesCollection } from 'antlr4-c3';
|
|
3
3
|
import { SQLParserBase } from '../../lib/SQLParserBase';
|
|
4
4
|
import { TextSlice } from './textAndWord';
|
|
5
|
-
import { CaretPosition, Suggestions } from './types';
|
|
5
|
+
import { CaretPosition, LOCALE_TYPE, Suggestions } from './types';
|
|
6
6
|
import { ParseError, ErrorListener } from './parseErrorListener';
|
|
7
7
|
import type { SplitListener } from './splitListener';
|
|
8
8
|
import type { EntityCollector } from './entityCollector';
|
|
@@ -40,17 +40,21 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
|
|
|
40
40
|
* @param candidates candidate list
|
|
41
41
|
* @param allTokens all tokens from input
|
|
42
42
|
* @param caretTokenIndex tokenIndex of caretPosition
|
|
43
|
-
* @param tokenIndexOffset offset of the tokenIndex in the candidates compared to the tokenIndex in allTokens
|
|
44
43
|
*/
|
|
45
|
-
protected abstract processCandidates(candidates: CandidatesCollection, allTokens: Token[], caretTokenIndex: number
|
|
44
|
+
protected abstract processCandidates(candidates: CandidatesCollection, allTokens: Token[], caretTokenIndex: number): Suggestions<Token>;
|
|
46
45
|
/**
|
|
47
46
|
* Get a new splitListener instance.
|
|
48
47
|
*/
|
|
49
48
|
protected abstract get splitListener(): SplitListener<ParserRuleContext>;
|
|
49
|
+
/**
|
|
50
|
+
* Get a new errorListener instance.
|
|
51
|
+
*/
|
|
52
|
+
protected abstract createErrorListener(errorListener: ErrorListener): ANTLRErrorListener;
|
|
50
53
|
/**
|
|
51
54
|
* Get a new entityCollector instance.
|
|
52
55
|
*/
|
|
53
56
|
protected abstract createEntityCollector(input: string, caretTokenIndex?: number): EntityCollector;
|
|
57
|
+
locale: LOCALE_TYPE;
|
|
54
58
|
/**
|
|
55
59
|
* Create an antlr4 lexer from input.
|
|
56
60
|
* @param input string
|
|
@@ -106,6 +110,7 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
|
|
|
106
110
|
* @param input source string
|
|
107
111
|
*/
|
|
108
112
|
splitSQLByStatement(input: string): TextSlice[] | null;
|
|
113
|
+
private splitInputBySeparator;
|
|
109
114
|
/**
|
|
110
115
|
* Get suggestions of syntax and token at caretPosition
|
|
111
116
|
* @param input source string
|
|
@@ -2,8 +2,8 @@ import { CharStreams, CommonTokenStream, ParseTreeWalker, PredictionMode, } from
|
|
|
2
2
|
import { CodeCompletionCore } from 'antlr4-c3';
|
|
3
3
|
import { findCaretTokenIndex } from './findCaretTokenIndex';
|
|
4
4
|
import { ctxToText, tokenToWord } from './textAndWord';
|
|
5
|
-
import { ParseErrorListener } from './parseErrorListener';
|
|
6
5
|
import { ErrorStrategy } from './errorStrategy';
|
|
6
|
+
const SEPARATOR = ';';
|
|
7
7
|
/**
|
|
8
8
|
* Basic SQL class, every sql needs extends it.
|
|
9
9
|
*/
|
|
@@ -14,6 +14,7 @@ export class BasicSQL {
|
|
|
14
14
|
this._errorListener = (error) => {
|
|
15
15
|
this._parseErrors.push(error);
|
|
16
16
|
};
|
|
17
|
+
this.locale = 'en_US';
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Create an antlr4 lexer from input.
|
|
@@ -24,7 +25,7 @@ export class BasicSQL {
|
|
|
24
25
|
const lexer = this.createLexerFromCharStream(charStreams);
|
|
25
26
|
if (errorListener) {
|
|
26
27
|
lexer.removeErrorListeners();
|
|
27
|
-
lexer.addErrorListener(
|
|
28
|
+
lexer.addErrorListener(this.createErrorListener(errorListener));
|
|
28
29
|
}
|
|
29
30
|
return lexer;
|
|
30
31
|
}
|
|
@@ -39,7 +40,7 @@ export class BasicSQL {
|
|
|
39
40
|
parser.interpreter.predictionMode = PredictionMode.SLL;
|
|
40
41
|
if (errorListener) {
|
|
41
42
|
parser.removeErrorListeners();
|
|
42
|
-
parser.addErrorListener(
|
|
43
|
+
parser.addErrorListener(this.createErrorListener(errorListener));
|
|
43
44
|
}
|
|
44
45
|
return parser;
|
|
45
46
|
}
|
|
@@ -65,7 +66,7 @@ export class BasicSQL {
|
|
|
65
66
|
this._charStreams = CharStreams.fromString(input);
|
|
66
67
|
this._lexer = this.createLexerFromCharStream(this._charStreams);
|
|
67
68
|
this._lexer.removeErrorListeners();
|
|
68
|
-
this._lexer.addErrorListener(
|
|
69
|
+
this._lexer.addErrorListener(this.createErrorListener(this._errorListener));
|
|
69
70
|
this._tokenStream = new CommonTokenStream(this._lexer);
|
|
70
71
|
/**
|
|
71
72
|
* All tokens are generated in advance.
|
|
@@ -96,7 +97,7 @@ export class BasicSQL {
|
|
|
96
97
|
const parser = this.createParserWithCache(input);
|
|
97
98
|
this._parsedInput = input;
|
|
98
99
|
parser.removeErrorListeners();
|
|
99
|
-
parser.addErrorListener(
|
|
100
|
+
parser.addErrorListener(this.createErrorListener(this._errorListener));
|
|
100
101
|
this._parseTree = parser.program();
|
|
101
102
|
return this._parseTree;
|
|
102
103
|
}
|
|
@@ -140,9 +141,6 @@ export class BasicSQL {
|
|
|
140
141
|
return null;
|
|
141
142
|
}
|
|
142
143
|
const splitListener = this.splitListener;
|
|
143
|
-
// TODO: add splitListener to all sqlParser implements and remove following if
|
|
144
|
-
if (!splitListener)
|
|
145
|
-
return null;
|
|
146
144
|
this.listen(splitListener, this._parseTree);
|
|
147
145
|
const res = splitListener.statementsContext
|
|
148
146
|
.map((context) => {
|
|
@@ -151,6 +149,39 @@ export class BasicSQL {
|
|
|
151
149
|
.filter(Boolean);
|
|
152
150
|
return res;
|
|
153
151
|
}
|
|
152
|
+
// 通过分隔符进一步切分语句
|
|
153
|
+
splitInputBySeparator(inputSlice, caretTokenIndex) {
|
|
154
|
+
const allTokens = this.getAllTokens(inputSlice);
|
|
155
|
+
/**
|
|
156
|
+
* set startToken
|
|
157
|
+
*/
|
|
158
|
+
let startToken = null;
|
|
159
|
+
for (let tokenIndex = caretTokenIndex; tokenIndex >= 0; tokenIndex--) {
|
|
160
|
+
const token = allTokens[tokenIndex];
|
|
161
|
+
if ((token === null || token === void 0 ? void 0 : token.text) === SEPARATOR) {
|
|
162
|
+
startToken = allTokens[tokenIndex + 1];
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (startToken === null) {
|
|
167
|
+
startToken = allTokens[0];
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* set stopToken
|
|
171
|
+
*/
|
|
172
|
+
let stopToken = null;
|
|
173
|
+
for (let tokenIndex = caretTokenIndex; tokenIndex < allTokens.length; tokenIndex++) {
|
|
174
|
+
const token = allTokens[tokenIndex];
|
|
175
|
+
if ((token === null || token === void 0 ? void 0 : token.text) === SEPARATOR) {
|
|
176
|
+
stopToken = token;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (stopToken === null) {
|
|
181
|
+
stopToken = allTokens[allTokens.length - 1];
|
|
182
|
+
}
|
|
183
|
+
return { startToken, stopToken };
|
|
184
|
+
}
|
|
154
185
|
/**
|
|
155
186
|
* Get suggestions of syntax and token at caretPosition
|
|
156
187
|
* @param input source string
|
|
@@ -158,16 +189,13 @@ export class BasicSQL {
|
|
|
158
189
|
* @returns suggestion
|
|
159
190
|
*/
|
|
160
191
|
getSuggestionAtCaretPosition(input, caretPosition) {
|
|
161
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
192
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
162
193
|
const splitListener = this.splitListener;
|
|
163
|
-
// TODO: add splitListener to all sqlParser implements and remove following if
|
|
164
|
-
if (!splitListener)
|
|
165
|
-
return null;
|
|
166
194
|
this.parseWithCache(input);
|
|
167
195
|
if (!this._parseTree)
|
|
168
196
|
return null;
|
|
169
197
|
let sqlParserIns = this._parser;
|
|
170
|
-
|
|
198
|
+
let allTokens = this.getAllTokens(input);
|
|
171
199
|
let caretTokenIndex = findCaretTokenIndex(caretPosition, allTokens);
|
|
172
200
|
let c3Context = this._parseTree;
|
|
173
201
|
let tokenIndexOffset = 0;
|
|
@@ -212,8 +240,8 @@ export class BasicSQL {
|
|
|
212
240
|
}
|
|
213
241
|
}
|
|
214
242
|
// A boundary consisting of the index of the input.
|
|
215
|
-
|
|
216
|
-
|
|
243
|
+
let startIndex = (_e = (_d = startStatement === null || startStatement === void 0 ? void 0 : startStatement.start) === null || _d === void 0 ? void 0 : _d.start) !== null && _e !== void 0 ? _e : 0;
|
|
244
|
+
let stopIndex = (_g = (_f = stopStatement === null || stopStatement === void 0 ? void 0 : stopStatement.stop) === null || _f === void 0 ? void 0 : _f.stop) !== null && _g !== void 0 ? _g : input.length - 1;
|
|
217
245
|
/**
|
|
218
246
|
* Save offset of the tokenIndex in the range of input
|
|
219
247
|
* compared to the tokenIndex in the whole input
|
|
@@ -224,7 +252,26 @@ export class BasicSQL {
|
|
|
224
252
|
* Reparse the input fragment,
|
|
225
253
|
* and c3 will collect candidates in the newly generated parseTree.
|
|
226
254
|
*/
|
|
227
|
-
|
|
255
|
+
let inputSlice = input.slice(startIndex, stopIndex);
|
|
256
|
+
/**
|
|
257
|
+
* Split the inputSlice by separator.
|
|
258
|
+
*/
|
|
259
|
+
if (inputSlice.includes(SEPARATOR)) {
|
|
260
|
+
const { startToken, stopToken } = this.splitInputBySeparator(inputSlice, caretTokenIndex);
|
|
261
|
+
startIndex = (_k = startToken === null || startToken === void 0 ? void 0 : startToken.start) !== null && _k !== void 0 ? _k : 0;
|
|
262
|
+
stopIndex = (_l = (stopToken === null || stopToken === void 0 ? void 0 : stopToken.stop) + 1) !== null && _l !== void 0 ? _l : input.length;
|
|
263
|
+
/**
|
|
264
|
+
* Save offset of the tokenIndex in the range of input
|
|
265
|
+
* compared to the tokenIndex in the whole input
|
|
266
|
+
*/
|
|
267
|
+
tokenIndexOffset = (_m = startToken === null || startToken === void 0 ? void 0 : startToken.tokenIndex) !== null && _m !== void 0 ? _m : 0;
|
|
268
|
+
caretTokenIndex = caretTokenIndex - tokenIndexOffset;
|
|
269
|
+
/**
|
|
270
|
+
* Get the smaller range of inputSlice
|
|
271
|
+
*/
|
|
272
|
+
inputSlice = inputSlice.slice(startIndex, stopIndex);
|
|
273
|
+
allTokens = this.getAllTokens(inputSlice);
|
|
274
|
+
}
|
|
228
275
|
const lexer = this.createLexer(inputSlice);
|
|
229
276
|
lexer.removeErrorListeners();
|
|
230
277
|
const tokenStream = new CommonTokenStream(lexer);
|
|
@@ -240,7 +287,7 @@ export class BasicSQL {
|
|
|
240
287
|
const core = new CodeCompletionCore(sqlParserIns);
|
|
241
288
|
core.preferredRules = this.preferredRules;
|
|
242
289
|
const candidates = core.collectCandidates(caretTokenIndex, c3Context);
|
|
243
|
-
const originalSuggestions = this.processCandidates(candidates, allTokens, caretTokenIndex
|
|
290
|
+
const originalSuggestions = this.processCandidates(candidates, allTokens, caretTokenIndex);
|
|
244
291
|
const syntaxSuggestions = originalSuggestions.syntax.map((syntaxCtx) => {
|
|
245
292
|
const wordRanges = syntaxCtx.wordRanges.map((token) => {
|
|
246
293
|
return tokenToWord(token, this._parsedInput);
|
|
@@ -261,10 +308,6 @@ export class BasicSQL {
|
|
|
261
308
|
? findCaretTokenIndex(caretPosition, allTokens)
|
|
262
309
|
: void 0;
|
|
263
310
|
const collectListener = this.createEntityCollector(input, caretTokenIndex);
|
|
264
|
-
// TODO: add entityCollector to all sqlParser implements and remove following if
|
|
265
|
-
if (!collectListener) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
311
|
// const parser = this.createParserWithCache(input);
|
|
269
312
|
// parser.entityCollecting = true;
|
|
270
313
|
// if(caretPosition) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ParserRuleContext } from 'antlr4ng';
|
|
1
|
+
import { ParserRuleContext, Token } from 'antlr4ng';
|
|
2
|
+
import { TextPosition, WordPosition, WordRange } from './textAndWord';
|
|
2
3
|
import { EntityContextType } from './types';
|
|
3
|
-
import { WordPosition, TextPosition } from './textAndWord';
|
|
4
4
|
/**
|
|
5
5
|
* TODO: more stmt type should be supported.
|
|
6
6
|
*/
|
|
@@ -13,7 +13,8 @@ export declare enum StmtContextType {
|
|
|
13
13
|
CREATE_VIEW_STMT = "createViewStmt",
|
|
14
14
|
SELECT_STMT = "selectStmt",
|
|
15
15
|
INSERT_STMT = "insertStmt",
|
|
16
|
-
CREATE_FUNCTION_STMT = "createFunctionStmt"
|
|
16
|
+
CREATE_FUNCTION_STMT = "createFunctionStmt",
|
|
17
|
+
ALTER_TABLE_STMT = "alterTableStmt"
|
|
17
18
|
}
|
|
18
19
|
export interface StmtContext {
|
|
19
20
|
readonly stmtContextType: StmtContextType;
|
|
@@ -23,20 +24,65 @@ export interface StmtContext {
|
|
|
23
24
|
readonly isContainCaret?: boolean;
|
|
24
25
|
}
|
|
25
26
|
export declare function toStmtContext(ctx: ParserRuleContext, type: StmtContextType, input: string, rootStmt: StmtContext | null, parentStmt: StmtContext | null, isContainCaret?: boolean): StmtContext | null;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
/**
|
|
28
|
+
* entity's attribute
|
|
29
|
+
* @key comment: entity's comment attribute
|
|
30
|
+
* @key colType: column entity's type attribute
|
|
31
|
+
* @key alias: entity's alias attribute
|
|
32
|
+
* */
|
|
33
|
+
export declare enum AttrName {
|
|
34
|
+
comment = "_comment",
|
|
35
|
+
colType = "_colType",
|
|
36
|
+
alias = "_alias"
|
|
30
37
|
}
|
|
31
|
-
|
|
38
|
+
/**
|
|
39
|
+
* ParserRuleContext with custom attributes
|
|
40
|
+
* */
|
|
41
|
+
type ParserRuleContextWithAttr = ParserRuleContext & {
|
|
42
|
+
[K in AttrName]?: Token;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Function's arguments
|
|
46
|
+
* */
|
|
47
|
+
export interface Argument {
|
|
48
|
+
argMode?: WordRange;
|
|
49
|
+
argName?: WordRange;
|
|
50
|
+
argType: WordRange;
|
|
51
|
+
}
|
|
52
|
+
export interface BaseEntityContext {
|
|
32
53
|
readonly entityContextType: EntityContextType;
|
|
33
54
|
readonly text: string;
|
|
34
55
|
readonly position: WordPosition;
|
|
35
56
|
readonly belongStmt: StmtContext;
|
|
36
|
-
|
|
37
|
-
|
|
57
|
+
reference?: string | EntityContext;
|
|
58
|
+
[AttrName.comment]: WordRange | null;
|
|
59
|
+
[AttrName.alias]?: WordRange | null;
|
|
60
|
+
}
|
|
61
|
+
export interface CommonEntityContext extends BaseEntityContext {
|
|
62
|
+
relatedEntities: CommonEntityContext[] | null;
|
|
63
|
+
columns?: ColumnEntityContext[];
|
|
64
|
+
}
|
|
65
|
+
export interface ColumnEntityContext extends BaseEntityContext {
|
|
66
|
+
[AttrName.colType]: WordRange | null;
|
|
67
|
+
}
|
|
68
|
+
export interface FuncEntityContext extends BaseEntityContext {
|
|
69
|
+
relatedEntities: CommonEntityContext[] | null;
|
|
70
|
+
arguments: Argument[] | null;
|
|
71
|
+
returns?: Argument;
|
|
72
|
+
}
|
|
73
|
+
export type EntityContext = CommonEntityContext | FuncEntityContext | ColumnEntityContext;
|
|
74
|
+
export declare function isCommonEntityContext(entity: EntityContext): entity is CommonEntityContext;
|
|
75
|
+
export declare function isFuncEntityContext(entity: EntityContext): entity is FuncEntityContext;
|
|
76
|
+
export declare function isColumnEntityContext(entity: EntityContext): entity is ColumnEntityContext;
|
|
77
|
+
/**
|
|
78
|
+
* what we need when collect attribute information
|
|
79
|
+
* */
|
|
80
|
+
interface AttrInfo {
|
|
81
|
+
attrName: AttrName;
|
|
82
|
+
endContextList: string[];
|
|
38
83
|
}
|
|
39
|
-
export declare function toEntityContext(ctx: ParserRuleContext, type: EntityContextType, input: string, belongStmt: StmtContext,
|
|
84
|
+
export declare function toEntityContext(ctx: ParserRuleContext, type: EntityContextType, input: string, belongStmt: StmtContext, attrInfo?: AttrInfo[]): EntityContext | null;
|
|
85
|
+
export declare function findAttribute(ctx: ParserRuleContextWithAttr | null, keyName: AttrName, endContextNameList: string[]): Token | null;
|
|
40
86
|
/**
|
|
41
87
|
* @todo: Handle alias, includes column alias, table alias, query as alias and so on.
|
|
42
88
|
* @todo: [may be need] Combine the entities in each clause.
|
|
@@ -59,11 +105,12 @@ export declare abstract class EntityCollector {
|
|
|
59
105
|
visitErrorNode(): void;
|
|
60
106
|
enterEveryRule(): void;
|
|
61
107
|
exitEveryRule(): void;
|
|
108
|
+
getRootStmt(): StmtContext | null;
|
|
62
109
|
getEntities(): EntityContext[];
|
|
63
110
|
enterProgram(): void;
|
|
64
111
|
protected pushStmt(ctx: ParserRuleContext, type: StmtContextType): StmtContext | null;
|
|
65
112
|
protected popStmt(): StmtContext;
|
|
66
|
-
protected pushEntity(ctx: ParserRuleContext, type: EntityContextType,
|
|
113
|
+
protected pushEntity(ctx: ParserRuleContext, type: EntityContextType, attrInfo?: AttrInfo[]): EntityContext | null;
|
|
67
114
|
/**
|
|
68
115
|
* Combine entities that inside a single statement.
|
|
69
116
|
* e.g. combine tableName and column if they are inside a same createTableStatement.
|
|
@@ -76,3 +123,4 @@ export declare abstract class EntityCollector {
|
|
|
76
123
|
protected combineRootStmtEntities(stmtContext: StmtContext, entitiesInsideStmt: EntityContext[]): EntityContext[];
|
|
77
124
|
protected combineCreateTableOrViewStmtEntities(stmtContext: StmtContext, entitiesInsideStmt: EntityContext[]): EntityContext[];
|
|
78
125
|
}
|
|
126
|
+
export {};
|
|
@@ -9,9 +9,10 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import {
|
|
13
|
-
import { ctxToText, ctxToWord } from './textAndWord';
|
|
12
|
+
import { isToken } from 'antlr4ng';
|
|
14
13
|
import { SimpleStack } from './simpleStack';
|
|
14
|
+
import { ctxToText, isWordRange, tokenToWord, } from './textAndWord';
|
|
15
|
+
import { EntityContextType } from './types';
|
|
15
16
|
/**
|
|
16
17
|
* TODO: more stmt type should be supported.
|
|
17
18
|
*/
|
|
@@ -26,6 +27,7 @@ export var StmtContextType;
|
|
|
26
27
|
StmtContextType["SELECT_STMT"] = "selectStmt";
|
|
27
28
|
StmtContextType["INSERT_STMT"] = "insertStmt";
|
|
28
29
|
StmtContextType["CREATE_FUNCTION_STMT"] = "createFunctionStmt";
|
|
30
|
+
StmtContextType["ALTER_TABLE_STMT"] = "alterTableStmt";
|
|
29
31
|
})(StmtContextType || (StmtContextType = {}));
|
|
30
32
|
export function toStmtContext(ctx, type, input, rootStmt, parentStmt, isContainCaret) {
|
|
31
33
|
const text = ctxToText(ctx, input);
|
|
@@ -40,20 +42,131 @@ export function toStmtContext(ctx, type, input, rootStmt, parentStmt, isContainC
|
|
|
40
42
|
isContainCaret,
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
/**
|
|
46
|
+
* entity's attribute
|
|
47
|
+
* @key comment: entity's comment attribute
|
|
48
|
+
* @key colType: column entity's type attribute
|
|
49
|
+
* @key alias: entity's alias attribute
|
|
50
|
+
* */
|
|
51
|
+
export var AttrName;
|
|
52
|
+
(function (AttrName) {
|
|
53
|
+
AttrName["comment"] = "_comment";
|
|
54
|
+
AttrName["colType"] = "_colType";
|
|
55
|
+
AttrName["alias"] = "_alias";
|
|
56
|
+
})(AttrName || (AttrName = {}));
|
|
57
|
+
export function isCommonEntityContext(entity) {
|
|
58
|
+
if (!entity)
|
|
59
|
+
return false;
|
|
60
|
+
return 'relatedEntities' in entity && !('arguments' in entity);
|
|
61
|
+
}
|
|
62
|
+
export function isFuncEntityContext(entity) {
|
|
63
|
+
if (!entity)
|
|
64
|
+
return false;
|
|
65
|
+
return 'arguments' in entity;
|
|
66
|
+
}
|
|
67
|
+
export function isColumnEntityContext(entity) {
|
|
68
|
+
if (!entity)
|
|
69
|
+
return false;
|
|
70
|
+
return AttrName.colType in entity;
|
|
71
|
+
}
|
|
72
|
+
export function toEntityContext(ctx, type, input, belongStmt, attrInfo) {
|
|
73
|
+
var _a, _b;
|
|
74
|
+
const word = ctxToText(ctx, input);
|
|
50
75
|
if (!word)
|
|
51
76
|
return null;
|
|
52
|
-
const { text } = word,
|
|
53
|
-
const
|
|
54
|
-
|
|
77
|
+
const { text, startLine, endLine } = word, rest = __rest(word, ["text", "startLine", "endLine"]);
|
|
78
|
+
const position = Object.assign(Object.assign({}, rest), { line: startLine });
|
|
79
|
+
let entityInfo = {
|
|
80
|
+
entityContextType: type,
|
|
81
|
+
text,
|
|
55
82
|
position,
|
|
56
|
-
belongStmt,
|
|
83
|
+
belongStmt,
|
|
84
|
+
[AttrName.comment]: null,
|
|
85
|
+
};
|
|
86
|
+
switch (entityInfo.entityContextType) {
|
|
87
|
+
case EntityContextType.FUNCTION:
|
|
88
|
+
case EntityContextType.FUNCTION_CREATE: {
|
|
89
|
+
entityInfo.relatedEntities = null;
|
|
90
|
+
entityInfo.arguments = null;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case EntityContextType.COLUMN:
|
|
94
|
+
case EntityContextType.COLUMN_CREATE:
|
|
95
|
+
entityInfo[AttrName.colType] = null;
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
entityInfo.relatedEntities = null;
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (attrInfo) {
|
|
102
|
+
for (let k = 0; k < attrInfo.length; k++) {
|
|
103
|
+
const attributeName = (_a = attrInfo[k]) === null || _a === void 0 ? void 0 : _a.attrName;
|
|
104
|
+
const attrToken = findAttribute(ctx, attributeName, (_b = attrInfo[k]) === null || _b === void 0 ? void 0 : _b.endContextList);
|
|
105
|
+
if (attrToken) {
|
|
106
|
+
const attrVal = isToken(attrToken)
|
|
107
|
+
? tokenToWord(attrToken, input)
|
|
108
|
+
: ctxToText(attrToken, input);
|
|
109
|
+
if (attrVal) {
|
|
110
|
+
if (isWordRange(attrVal)) {
|
|
111
|
+
entityInfo = Object.assign(entityInfo, {
|
|
112
|
+
[attributeName]: attrVal,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const { startIndex, endIndex, startColumn, endColumn, text } = attrVal, rest = __rest(attrVal, ["startIndex", "endIndex", "startColumn", "endColumn", "text"]);
|
|
117
|
+
entityInfo = Object.assign(entityInfo, {
|
|
118
|
+
[attributeName]: {
|
|
119
|
+
startIndex,
|
|
120
|
+
endIndex,
|
|
121
|
+
startColumn,
|
|
122
|
+
endColumn,
|
|
123
|
+
text,
|
|
124
|
+
line: rest === null || rest === void 0 ? void 0 : rest.startLine,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return entityInfo;
|
|
133
|
+
}
|
|
134
|
+
export function findAttribute(ctx, keyName, endContextNameList) {
|
|
135
|
+
var _a, _b;
|
|
136
|
+
const parent = (ctx === null || ctx === void 0 ? void 0 : ctx.parent) || null;
|
|
137
|
+
let attrVal = null;
|
|
138
|
+
if (parent === null || parent === void 0 ? void 0 : parent[keyName]) {
|
|
139
|
+
attrVal = (parent === null || parent === void 0 ? void 0 : parent[keyName]) || null;
|
|
140
|
+
return attrVal;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
if (((_a = parent === null || parent === void 0 ? void 0 : parent.constructor) === null || _a === void 0 ? void 0 : _a.name) && !endContextNameList.includes((_b = parent === null || parent === void 0 ? void 0 : parent.constructor) === null || _b === void 0 ? void 0 : _b.name)) {
|
|
144
|
+
attrVal = findAttribute(parent, keyName, endContextNameList);
|
|
145
|
+
}
|
|
146
|
+
if (!attrVal) {
|
|
147
|
+
if (parent === null || parent === void 0 ? void 0 : parent.children) {
|
|
148
|
+
attrVal = findAttributeChildren(parent, keyName);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return attrVal;
|
|
153
|
+
}
|
|
154
|
+
function findAttributeChildren(ctx, keyName) {
|
|
155
|
+
const visitChildren = (ctx === null || ctx === void 0 ? void 0 : ctx.children) || [];
|
|
156
|
+
let attrVal = null;
|
|
157
|
+
if (visitChildren.length) {
|
|
158
|
+
for (let i = 0; i < visitChildren.length; i++) {
|
|
159
|
+
const child = visitChildren[i] || null;
|
|
160
|
+
if (child === null || child === void 0 ? void 0 : child[keyName]) {
|
|
161
|
+
attrVal = (child === null || child === void 0 ? void 0 : child[keyName]) || null;
|
|
162
|
+
return attrVal;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
attrVal = findAttributeChildren(child, keyName);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return attrVal;
|
|
57
170
|
}
|
|
58
171
|
/**
|
|
59
172
|
* @todo: Handle alias, includes column alias, table alias, query as alias and so on.
|
|
@@ -72,6 +185,9 @@ export class EntityCollector {
|
|
|
72
185
|
visitErrorNode() { }
|
|
73
186
|
enterEveryRule() { }
|
|
74
187
|
exitEveryRule() { }
|
|
188
|
+
getRootStmt() {
|
|
189
|
+
return this._rootStmt;
|
|
190
|
+
}
|
|
75
191
|
getEntities() {
|
|
76
192
|
return Array.from(this._entitiesSet);
|
|
77
193
|
}
|
|
@@ -111,8 +227,8 @@ export class EntityCollector {
|
|
|
111
227
|
}
|
|
112
228
|
return stmtContext;
|
|
113
229
|
}
|
|
114
|
-
pushEntity(ctx, type,
|
|
115
|
-
const entityContext = toEntityContext(ctx, type, this._input, this._stmtStack.peek(),
|
|
230
|
+
pushEntity(ctx, type, attrInfo) {
|
|
231
|
+
const entityContext = toEntityContext(ctx, type, this._input, this._stmtStack.peek(), attrInfo);
|
|
116
232
|
if (entityContext) {
|
|
117
233
|
if (this._stmtStack.isEmpty()) {
|
|
118
234
|
this._entitiesSet.add(entityContext);
|
|
@@ -181,10 +297,18 @@ export class EntityCollector {
|
|
|
181
297
|
return result;
|
|
182
298
|
}, []);
|
|
183
299
|
if (mainEntity && columns.length) {
|
|
184
|
-
mainEntity
|
|
300
|
+
if (isCommonEntityContext(mainEntity)) {
|
|
301
|
+
mainEntity = Object.assign(mainEntity, {
|
|
302
|
+
columns,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
185
305
|
}
|
|
186
306
|
if (mainEntity && relatedEntities.length) {
|
|
187
|
-
mainEntity
|
|
307
|
+
if (isCommonEntityContext(mainEntity) || isFuncEntityContext(mainEntity)) {
|
|
308
|
+
mainEntity = Object.assign(mainEntity, {
|
|
309
|
+
relatedEntities,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
188
312
|
}
|
|
189
313
|
return finalEntities;
|
|
190
314
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { Token, Recognizer, ANTLRErrorListener, RecognitionException, ATNSimulator } from 'antlr4ng';
|
|
1
|
+
import { Token, Recognizer, ANTLRErrorListener, RecognitionException, ATNSimulator, Parser } from 'antlr4ng';
|
|
2
|
+
import { LOCALE_TYPE } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* Converted from {@link SyntaxError}.
|
|
4
5
|
*/
|
|
@@ -29,11 +30,13 @@ export interface SyntaxError {
|
|
|
29
30
|
* Includes lexical errors and parsing errors.
|
|
30
31
|
*/
|
|
31
32
|
export type ErrorListener = (parseError: ParseError, originalError: SyntaxError) => void;
|
|
32
|
-
export declare class ParseErrorListener implements ANTLRErrorListener {
|
|
33
|
+
export declare abstract class ParseErrorListener implements ANTLRErrorListener {
|
|
33
34
|
private _errorListener;
|
|
34
|
-
|
|
35
|
+
private locale;
|
|
36
|
+
constructor(errorListener: ErrorListener, locale?: LOCALE_TYPE);
|
|
35
37
|
reportAmbiguity(): void;
|
|
36
38
|
reportAttemptingFullContext(): void;
|
|
37
39
|
reportContextSensitivity(): void;
|
|
40
|
+
protected abstract getExpectedText(parser: Parser, token: Token): string;
|
|
38
41
|
syntaxError(recognizer: Recognizer<ATNSimulator>, offendingSymbol: Token | null, line: number, charPositionInLine: number, msg: string, e: RecognitionException): void;
|
|
39
42
|
}
|