dt-sql-parser 4.0.1 → 4.1.0-beta.0
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 +11463 -10512
- package/dist/lib/mysql/MySqlParserListener.d.ts +42 -20
- package/dist/lib/mysql/MySqlParserVisitor.d.ts +26 -12
- 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 +7 -2
- package/dist/parser/common/basicSQL.js +5 -15
- 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 +3 -0
- package/dist/parser/flink/index.js +13 -9
- 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 +3 -0
- package/dist/parser/hive/index.js +13 -9
- 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 +3 -0
- package/dist/parser/impala/index.js +4 -0
- package/dist/parser/mysql/index.d.ts +3 -0
- package/dist/parser/mysql/index.js +4 -0
- 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 +3 -0
- package/dist/parser/postgresql/index.js +17 -13
- 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 +3 -0
- package/dist/parser/spark/index.js +4 -0
- 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 +3 -0
- package/dist/parser/trino/index.js +23 -10
- 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 +40 -12
|
@@ -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';
|
|
@@ -47,10 +47,15 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
|
|
|
47
47
|
* Get a new splitListener instance.
|
|
48
48
|
*/
|
|
49
49
|
protected abstract get splitListener(): SplitListener<ParserRuleContext>;
|
|
50
|
+
/**
|
|
51
|
+
* Get a new errorListener instance.
|
|
52
|
+
*/
|
|
53
|
+
protected abstract createErrorListener(errorListener: ErrorListener): ANTLRErrorListener;
|
|
50
54
|
/**
|
|
51
55
|
* Get a new entityCollector instance.
|
|
52
56
|
*/
|
|
53
57
|
protected abstract createEntityCollector(input: string, caretTokenIndex?: number): EntityCollector;
|
|
58
|
+
locale: LOCALE_TYPE;
|
|
54
59
|
/**
|
|
55
60
|
* Create an antlr4 lexer from input.
|
|
56
61
|
* @param input string
|
|
@@ -2,7 +2,6 @@ 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';
|
|
7
6
|
/**
|
|
8
7
|
* Basic SQL class, every sql needs extends it.
|
|
@@ -14,6 +13,7 @@ export class BasicSQL {
|
|
|
14
13
|
this._errorListener = (error) => {
|
|
15
14
|
this._parseErrors.push(error);
|
|
16
15
|
};
|
|
16
|
+
this.locale = 'en_US';
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Create an antlr4 lexer from input.
|
|
@@ -24,7 +24,7 @@ export class BasicSQL {
|
|
|
24
24
|
const lexer = this.createLexerFromCharStream(charStreams);
|
|
25
25
|
if (errorListener) {
|
|
26
26
|
lexer.removeErrorListeners();
|
|
27
|
-
lexer.addErrorListener(
|
|
27
|
+
lexer.addErrorListener(this.createErrorListener(errorListener));
|
|
28
28
|
}
|
|
29
29
|
return lexer;
|
|
30
30
|
}
|
|
@@ -39,7 +39,7 @@ export class BasicSQL {
|
|
|
39
39
|
parser.interpreter.predictionMode = PredictionMode.SLL;
|
|
40
40
|
if (errorListener) {
|
|
41
41
|
parser.removeErrorListeners();
|
|
42
|
-
parser.addErrorListener(
|
|
42
|
+
parser.addErrorListener(this.createErrorListener(errorListener));
|
|
43
43
|
}
|
|
44
44
|
return parser;
|
|
45
45
|
}
|
|
@@ -65,7 +65,7 @@ export class BasicSQL {
|
|
|
65
65
|
this._charStreams = CharStreams.fromString(input);
|
|
66
66
|
this._lexer = this.createLexerFromCharStream(this._charStreams);
|
|
67
67
|
this._lexer.removeErrorListeners();
|
|
68
|
-
this._lexer.addErrorListener(
|
|
68
|
+
this._lexer.addErrorListener(this.createErrorListener(this._errorListener));
|
|
69
69
|
this._tokenStream = new CommonTokenStream(this._lexer);
|
|
70
70
|
/**
|
|
71
71
|
* All tokens are generated in advance.
|
|
@@ -96,7 +96,7 @@ export class BasicSQL {
|
|
|
96
96
|
const parser = this.createParserWithCache(input);
|
|
97
97
|
this._parsedInput = input;
|
|
98
98
|
parser.removeErrorListeners();
|
|
99
|
-
parser.addErrorListener(
|
|
99
|
+
parser.addErrorListener(this.createErrorListener(this._errorListener));
|
|
100
100
|
this._parseTree = parser.program();
|
|
101
101
|
return this._parseTree;
|
|
102
102
|
}
|
|
@@ -140,9 +140,6 @@ export class BasicSQL {
|
|
|
140
140
|
return null;
|
|
141
141
|
}
|
|
142
142
|
const splitListener = this.splitListener;
|
|
143
|
-
// TODO: add splitListener to all sqlParser implements and remove following if
|
|
144
|
-
if (!splitListener)
|
|
145
|
-
return null;
|
|
146
143
|
this.listen(splitListener, this._parseTree);
|
|
147
144
|
const res = splitListener.statementsContext
|
|
148
145
|
.map((context) => {
|
|
@@ -160,9 +157,6 @@ export class BasicSQL {
|
|
|
160
157
|
getSuggestionAtCaretPosition(input, caretPosition) {
|
|
161
158
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
162
159
|
const splitListener = this.splitListener;
|
|
163
|
-
// TODO: add splitListener to all sqlParser implements and remove following if
|
|
164
|
-
if (!splitListener)
|
|
165
|
-
return null;
|
|
166
160
|
this.parseWithCache(input);
|
|
167
161
|
if (!this._parseTree)
|
|
168
162
|
return null;
|
|
@@ -261,10 +255,6 @@ export class BasicSQL {
|
|
|
261
255
|
? findCaretTokenIndex(caretPosition, allTokens)
|
|
262
256
|
: void 0;
|
|
263
257
|
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
258
|
// const parser = this.createParserWithCache(input);
|
|
269
259
|
// parser.entityCollecting = true;
|
|
270
260
|
// 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
|
}
|
|
@@ -1,11 +1,92 @@
|
|
|
1
|
+
import { Token, LexerNoViableAltException, InputMismatchException, NoViableAltException, } from 'antlr4ng';
|
|
2
|
+
import { transform } from './transform';
|
|
1
3
|
export class ParseErrorListener {
|
|
2
|
-
constructor(errorListener) {
|
|
4
|
+
constructor(errorListener, locale = 'en_US') {
|
|
5
|
+
this.locale = locale;
|
|
3
6
|
this._errorListener = errorListener;
|
|
4
7
|
}
|
|
5
8
|
reportAmbiguity() { }
|
|
6
9
|
reportAttemptingFullContext() { }
|
|
7
10
|
reportContextSensitivity() { }
|
|
8
11
|
syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e) {
|
|
12
|
+
var _a;
|
|
13
|
+
let message = '';
|
|
14
|
+
// If not undefined then offendingSymbol is of type Token.
|
|
15
|
+
if (offendingSymbol) {
|
|
16
|
+
let token = offendingSymbol;
|
|
17
|
+
const parser = recognizer;
|
|
18
|
+
// judge token is EOF
|
|
19
|
+
const isEof = token.type === Token.EOF;
|
|
20
|
+
if (isEof) {
|
|
21
|
+
token = parser.tokenStream.get(token.tokenIndex - 1);
|
|
22
|
+
}
|
|
23
|
+
const wrongText = (_a = token.text) !== null && _a !== void 0 ? _a : '';
|
|
24
|
+
const isInComplete = isEof && wrongText !== ' ';
|
|
25
|
+
const expectedText = isInComplete ? '' : this.getExpectedText(parser, token);
|
|
26
|
+
if (!e) {
|
|
27
|
+
// handle missing or unwanted tokens.
|
|
28
|
+
message = msg;
|
|
29
|
+
if (msg.includes('extraneous')) {
|
|
30
|
+
message = `'${wrongText}' {noValidPosition}${expectedText.length ? `{expecting}${expectedText}` : ''}`;
|
|
31
|
+
}
|
|
32
|
+
if (msg.includes('missing')) {
|
|
33
|
+
const regex = /missing\s+'([^']+)'/;
|
|
34
|
+
const match = msg.match(regex);
|
|
35
|
+
message = `{missing}`;
|
|
36
|
+
if (match) {
|
|
37
|
+
const missKeyword = match[1];
|
|
38
|
+
message += `'${missKeyword}'`;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
message += `{keyword}`;
|
|
42
|
+
}
|
|
43
|
+
message += `{at}'${wrongText}'`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// handle mismatch exception or no viable alt exception
|
|
48
|
+
if (e instanceof InputMismatchException || e instanceof NoViableAltException) {
|
|
49
|
+
if (isEof) {
|
|
50
|
+
message = `{stmtInComplete}`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
message = `'${wrongText}' {noValidPosition}`;
|
|
54
|
+
}
|
|
55
|
+
if (expectedText.length > 0) {
|
|
56
|
+
message += `{expecting}${expectedText}`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
message = msg;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// No offending symbol, which indicates this is a lexer error.
|
|
66
|
+
if (e instanceof LexerNoViableAltException) {
|
|
67
|
+
const lexer = recognizer;
|
|
68
|
+
const input = lexer.inputStream;
|
|
69
|
+
let text = lexer.getErrorDisplay(input.getText(lexer._tokenStartCharIndex, input.index));
|
|
70
|
+
switch (text[0]) {
|
|
71
|
+
case '/':
|
|
72
|
+
message = '{unfinishedMultilineComment}';
|
|
73
|
+
break;
|
|
74
|
+
case '"':
|
|
75
|
+
message = '{unfinishedDoubleQuoted}';
|
|
76
|
+
break;
|
|
77
|
+
case "'":
|
|
78
|
+
message = '{unfinishedSingleQuoted}';
|
|
79
|
+
break;
|
|
80
|
+
case '`':
|
|
81
|
+
message = '{unfinishedTickQuoted}';
|
|
82
|
+
break;
|
|
83
|
+
default:
|
|
84
|
+
message = '"' + text + '" {noValidInput}';
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
message = transform(message, this.locale);
|
|
9
90
|
let endCol = charPositionInLine + 1;
|
|
10
91
|
if (offendingSymbol && offendingSymbol.text !== null) {
|
|
11
92
|
endCol = charPositionInLine + offendingSymbol.text.length;
|
|
@@ -16,7 +97,7 @@ export class ParseErrorListener {
|
|
|
16
97
|
endLine: line,
|
|
17
98
|
startColumn: charPositionInLine + 1,
|
|
18
99
|
endColumn: endCol + 1,
|
|
19
|
-
message
|
|
100
|
+
message,
|
|
20
101
|
}, {
|
|
21
102
|
e,
|
|
22
103
|
line,
|
|
@@ -35,18 +35,15 @@ export interface TextSlice extends TextPosition {
|
|
|
35
35
|
/**
|
|
36
36
|
* Convert Token to Word
|
|
37
37
|
*/
|
|
38
|
-
export declare function tokenToWord(token: Token, input: string):
|
|
39
|
-
text: string;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Convert ParserRuleContext to Word
|
|
43
|
-
*/
|
|
44
|
-
export declare function ctxToWord(ctx: ParserRuleContext, input: string): (WordPosition & {
|
|
45
|
-
text: string;
|
|
46
|
-
}) | null;
|
|
38
|
+
export declare function tokenToWord(token: Token, input: string): WordRange;
|
|
47
39
|
/**
|
|
48
40
|
* Convert ParserRuleContext to Text
|
|
49
41
|
*/
|
|
50
42
|
export declare function ctxToText(ctx: ParserRuleContext, input: string): (TextPosition & {
|
|
51
43
|
text: string;
|
|
52
44
|
}) | null;
|
|
45
|
+
/**
|
|
46
|
+
* judge whether the context is a WordRange
|
|
47
|
+
* @param textOrWord TextSlice or WordRange object
|
|
48
|
+
* */
|
|
49
|
+
export declare function isWordRange(textOrWord: TextSlice | WordRange): textOrWord is WordRange;
|