dt-sql-parser 4.5.1 → 4.5.2-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/dist/lib/flink/FlinkSqlParser.d.ts +220 -363
- package/dist/lib/flink/FlinkSqlParser.js +3246 -4046
- package/dist/lib/flink/FlinkSqlParserListener.d.ts +0 -154
- package/dist/lib/flink/FlinkSqlParserVisitor.d.ts +0 -98
- package/dist/lib/generic/GenericSqlListener.d.ts +11 -0
- package/dist/lib/generic/GenericSqlParser.d.ts +61 -47
- package/dist/lib/generic/GenericSqlParser.js +1047 -949
- package/dist/lib/generic/GenericSqlVisitor.d.ts +7 -0
- package/dist/lib/hive/HiveSqlParser.d.ts +515 -943
- package/dist/lib/hive/HiveSqlParser.js +8234 -10573
- package/dist/lib/hive/HiveSqlParserListener.d.ts +50 -490
- package/dist/lib/hive/HiveSqlParserVisitor.d.ts +30 -310
- package/dist/lib/impala/ImpalaSqlParser.d.ts +96 -131
- package/dist/lib/impala/ImpalaSqlParser.js +3311 -3522
- package/dist/lib/impala/ImpalaSqlParserListener.d.ts +0 -44
- package/dist/lib/impala/ImpalaSqlParserVisitor.d.ts +0 -28
- package/dist/lib/mysql/MySqlParser.d.ts +425 -465
- package/dist/lib/mysql/MySqlParser.js +10300 -10510
- package/dist/lib/mysql/MySqlParserListener.d.ts +0 -44
- package/dist/lib/mysql/MySqlParserVisitor.d.ts +0 -28
- package/dist/lib/postgresql/PostgreSqlParser.d.ts +181 -164
- package/dist/lib/postgresql/PostgreSqlParser.js +10273 -10121
- package/dist/lib/postgresql/PostgreSqlParserListener.d.ts +11 -0
- package/dist/lib/postgresql/PostgreSqlParserVisitor.d.ts +7 -0
- package/dist/lib/trino/TrinoSqlListener.d.ts +0 -328
- package/dist/lib/trino/TrinoSqlParser.d.ts +205 -477
- package/dist/lib/trino/TrinoSqlParser.js +6689 -7898
- package/dist/lib/trino/TrinoSqlVisitor.d.ts +0 -206
- package/dist/parser/common/entityCollector.d.ts +37 -2
- package/dist/parser/common/entityCollector.js +303 -2
- package/dist/parser/flink/flinkEntityCollector.d.ts +2 -1
- package/dist/parser/flink/flinkEntityCollector.js +4 -0
- package/dist/parser/generic/genericEntityCollector.d.ts +7 -2
- package/dist/parser/generic/genericEntityCollector.js +65 -15
- package/dist/parser/generic/index.js +12 -0
- package/dist/parser/hive/hiveEntityCollector.d.ts +2 -1
- package/dist/parser/hive/hiveEntityCollector.js +5 -0
- package/dist/parser/impala/impalaEntityCollector.d.ts +2 -1
- package/dist/parser/impala/impalaEntityCollector.js +4 -0
- package/dist/parser/mysql/mysqlEntityCollector.d.ts +2 -1
- package/dist/parser/mysql/mysqlEntityCollector.js +19 -0
- package/dist/parser/postgresql/postgreEntityCollector.d.ts +2 -1
- package/dist/parser/postgresql/postgreEntityCollector.js +5 -0
- package/dist/parser/spark/sparkEntityCollector.d.ts +2 -1
- package/dist/parser/spark/sparkEntityCollector.js +5 -0
- package/dist/parser/trino/trinoEntityCollector.d.ts +2 -1
- package/dist/parser/trino/trinoEntityCollector.js +5 -0
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
9
9
|
}
|
|
10
10
|
return t;
|
|
11
11
|
};
|
|
12
|
-
import { isToken, Token } from 'antlr4ng';
|
|
12
|
+
import { isToken, ParserRuleContext, TerminalNode, Token } from 'antlr4ng';
|
|
13
13
|
import { SimpleStack } from './simpleStack';
|
|
14
14
|
import { ctxToText, isWordRange, tokenToWord, } from './textAndWord';
|
|
15
15
|
import { EntityContextType } from './types';
|
|
@@ -224,24 +224,63 @@ function isEntityInScope(entity, rangeEntity) {
|
|
|
224
224
|
rangeStart <= entityStart &&
|
|
225
225
|
rangeStop >= entityStop);
|
|
226
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Parents of a single CTE item. The scope of that CTE is the query that owns this clause.
|
|
229
|
+
*/
|
|
230
|
+
const CTE_CLAUSE_CONTEXT_NAMES = new Set([
|
|
231
|
+
'WithClauseContext',
|
|
232
|
+
'WithStatementContext',
|
|
233
|
+
'CtesContext',
|
|
234
|
+
'WithContext',
|
|
235
|
+
]);
|
|
236
|
+
function normalizeIdent(text) {
|
|
237
|
+
let value = text.trim();
|
|
238
|
+
if ((value.startsWith('`') && value.endsWith('`') && value.length >= 2) ||
|
|
239
|
+
(value.startsWith('"') && value.endsWith('"') && value.length >= 2) ||
|
|
240
|
+
(value.startsWith('[') && value.endsWith(']') && value.length >= 2)) {
|
|
241
|
+
value = value.slice(1, -1);
|
|
242
|
+
}
|
|
243
|
+
return value.toLowerCase();
|
|
244
|
+
}
|
|
245
|
+
function sameIdent(left, right) {
|
|
246
|
+
return normalizeIdent(left) === normalizeIdent(right);
|
|
247
|
+
}
|
|
227
248
|
/**
|
|
228
249
|
* @todo: Handle alias, includes column alias, table alias, query as alias and so on.
|
|
229
250
|
* @todo: [may be need] Combine the entities in each clause.
|
|
230
251
|
*/
|
|
231
252
|
export class EntityCollector {
|
|
232
253
|
constructor(input, allTokens, caretTokenIndex) {
|
|
254
|
+
/**
|
|
255
|
+
* Contexts whose source slice contains a parse error.
|
|
256
|
+
* Error recovery can stretch a rule context across a whole clause, so `ctxToText`
|
|
257
|
+
* would return e.g. `JOIN myOwn\nORDER BY 1` where a name is expected.
|
|
258
|
+
*/
|
|
259
|
+
this._errorContexts = new Set();
|
|
233
260
|
this._input = input;
|
|
234
261
|
this._allTokens = allTokens || [];
|
|
235
262
|
this._caretTokenIndex = caretTokenIndex !== null && caretTokenIndex !== void 0 ? caretTokenIndex : -1;
|
|
236
263
|
this._entitiesSet = new Set();
|
|
237
264
|
this._stmtStack = new SimpleStack();
|
|
238
265
|
this._entityStack = new SimpleStack();
|
|
266
|
+
this._cteDefinitions = [];
|
|
239
267
|
this._rootStmt = null;
|
|
240
268
|
this._caretStmtScopeDepth = 0;
|
|
241
269
|
this._caretStmt = null;
|
|
242
270
|
}
|
|
243
271
|
visitTerminal() { }
|
|
244
|
-
visitErrorNode() {
|
|
272
|
+
visitErrorNode(node) {
|
|
273
|
+
/**
|
|
274
|
+
* Mark every ancestor. An entity pushed on one of them would carry the
|
|
275
|
+
* error-tainted source slice as its `text`. Entities are always pushed from
|
|
276
|
+
* `exit<Rule>` callbacks, so this runs before the context is used.
|
|
277
|
+
*/
|
|
278
|
+
let parent = node.parent;
|
|
279
|
+
while (parent) {
|
|
280
|
+
this._errorContexts.add(parent);
|
|
281
|
+
parent = parent.parent;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
245
284
|
enterEveryRule() { }
|
|
246
285
|
exitEveryRule() { }
|
|
247
286
|
getRootStmt() {
|
|
@@ -254,11 +293,16 @@ export class EntityCollector {
|
|
|
254
293
|
this._entitiesSet.clear();
|
|
255
294
|
this._stmtStack.clear();
|
|
256
295
|
this._entityStack.clear();
|
|
296
|
+
this._cteDefinitions = [];
|
|
257
297
|
this._rootStmt = null;
|
|
298
|
+
this._errorContexts.clear();
|
|
258
299
|
}
|
|
259
300
|
exitProgram() {
|
|
301
|
+
this.finalizeCteDefinitions();
|
|
302
|
+
this.bindCteReferences();
|
|
260
303
|
const entities = Array.from(this._entitiesSet);
|
|
261
304
|
if (this._caretTokenIndex !== -1) {
|
|
305
|
+
this.markCteAccessibility();
|
|
262
306
|
this.attachAccessibleToEntities(entities);
|
|
263
307
|
}
|
|
264
308
|
this._entityStack.clear();
|
|
@@ -376,6 +420,11 @@ export class EntityCollector {
|
|
|
376
420
|
if (!this._entityStack.isEmpty()) {
|
|
377
421
|
this.combineEntitiesAndAdd(stmtContext);
|
|
378
422
|
}
|
|
423
|
+
// Statement-scoped walks never exit program. Finalize once the outermost statement pops.
|
|
424
|
+
if (this._stmtStack.isEmpty()) {
|
|
425
|
+
this.finalizeCteDefinitions();
|
|
426
|
+
this.bindCteReferences();
|
|
427
|
+
}
|
|
379
428
|
// If the current statement contains the caret and its scope depth equals the caret statement's scope depth
|
|
380
429
|
// then set it as the nearest statement containing the caret
|
|
381
430
|
if (stmtContext.isContainCaret &&
|
|
@@ -386,6 +435,9 @@ export class EntityCollector {
|
|
|
386
435
|
return stmtContext;
|
|
387
436
|
}
|
|
388
437
|
pushEntity(ctx, type, attrInfo, metaInfo) {
|
|
438
|
+
// A context containing a parse error has no usable `text`.
|
|
439
|
+
if (this._errorContexts.has(ctx))
|
|
440
|
+
return null;
|
|
389
441
|
const entityContext = toEntityContext(ctx, type, this._input, this._stmtStack.peek(), attrInfo, metaInfo);
|
|
390
442
|
if (entityContext) {
|
|
391
443
|
if (this._stmtStack.isEmpty()) {
|
|
@@ -545,4 +597,253 @@ export class EntityCollector {
|
|
|
545
597
|
}
|
|
546
598
|
return finalEntities;
|
|
547
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Collect one CTE definition.
|
|
602
|
+
* `endTokenIndex` is the closing token of this item only (not a following CTE).
|
|
603
|
+
* Column names, when present, become the outward schema and do not replace the body query result.
|
|
604
|
+
*/
|
|
605
|
+
collectCte(cteCtx, nameCtx, bodyCtx, endTokenIndex, columnNameCtxs = [], columnListCtx = null) {
|
|
606
|
+
if (!nameCtx || endTokenIndex < 0)
|
|
607
|
+
return;
|
|
608
|
+
const entity = this.pushEntity(nameCtx, EntityContextType.TABLE, undefined, {
|
|
609
|
+
declareType: TableDeclareType.EXPRESSION,
|
|
610
|
+
});
|
|
611
|
+
if (!entity || !isCommonEntityContext(entity))
|
|
612
|
+
return;
|
|
613
|
+
this._cteDefinitions.push({
|
|
614
|
+
entity,
|
|
615
|
+
name: entity.text,
|
|
616
|
+
body: bodyCtx,
|
|
617
|
+
columnNameCtxs,
|
|
618
|
+
columnListCtx,
|
|
619
|
+
endTokenIndex,
|
|
620
|
+
scopeEndTokenIndex: this.cteScopeEndTokenIndex(cteCtx, endTokenIndex),
|
|
621
|
+
outward: null,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
cteScopeEndTokenIndex(cteCtx, endTokenIndex) {
|
|
625
|
+
var _a, _b, _c, _d, _e;
|
|
626
|
+
let scopeEnd = endTokenIndex;
|
|
627
|
+
let current = cteCtx.parent;
|
|
628
|
+
while (current) {
|
|
629
|
+
if (CTE_CLAUSE_CONTEXT_NAMES.has(current.constructor.name)) {
|
|
630
|
+
scopeEnd = (_c = (_b = (_a = current.parent) === null || _a === void 0 ? void 0 : _a.stop) === null || _b === void 0 ? void 0 : _b.tokenIndex) !== null && _c !== void 0 ? _c : endTokenIndex;
|
|
631
|
+
break;
|
|
632
|
+
}
|
|
633
|
+
current = current.parent;
|
|
634
|
+
}
|
|
635
|
+
if (!current) {
|
|
636
|
+
scopeEnd = (_e = (_d = this._stmtStack.peek()) === null || _d === void 0 ? void 0 : _d.position.endTokenIndex) !== null && _e !== void 0 ? _e : endTokenIndex;
|
|
637
|
+
}
|
|
638
|
+
// An incomplete FROM/JOIN stops the parsed query before the caret.
|
|
639
|
+
// Keep the CTE visible until a semicolon or a closing paren leaves this query.
|
|
640
|
+
return this.extendUnclosedScope(scopeEnd);
|
|
641
|
+
}
|
|
642
|
+
extendUnclosedScope(scopeEnd) {
|
|
643
|
+
var _a;
|
|
644
|
+
let depth = 0;
|
|
645
|
+
let end = scopeEnd;
|
|
646
|
+
for (let i = scopeEnd + 1; i < this._allTokens.length; i++) {
|
|
647
|
+
const token = this._allTokens[i];
|
|
648
|
+
if (token.channel === Token.HIDDEN_CHANNEL || token.type === Token.EOF)
|
|
649
|
+
continue;
|
|
650
|
+
const text = (_a = token.text) !== null && _a !== void 0 ? _a : '';
|
|
651
|
+
if (text === ';')
|
|
652
|
+
break;
|
|
653
|
+
if (text === '(') {
|
|
654
|
+
depth++;
|
|
655
|
+
}
|
|
656
|
+
else if (text === ')') {
|
|
657
|
+
if (depth === 0)
|
|
658
|
+
break;
|
|
659
|
+
depth--;
|
|
660
|
+
}
|
|
661
|
+
end = token.tokenIndex;
|
|
662
|
+
}
|
|
663
|
+
return end;
|
|
664
|
+
}
|
|
665
|
+
finalizeCteDefinitions() {
|
|
666
|
+
this._cteDefinitions.forEach((cte) => {
|
|
667
|
+
if (cte.outward) {
|
|
668
|
+
cte.entity.relatedEntities = [cte.outward];
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
const fromColumnList = cte.columnListCtx
|
|
672
|
+
? this.createColumnListQueryResultFromTokens(cte.entity.belongStmt, this.columnTokens(cte.columnListCtx))
|
|
673
|
+
: cte.columnNameCtxs.length
|
|
674
|
+
? this.createColumnListQueryResult(cte.entity.belongStmt, cte.columnNameCtxs)
|
|
675
|
+
: null;
|
|
676
|
+
const found = fromColumnList !== null && fromColumnList !== void 0 ? fromColumnList : this.findOutwardQueryResult(cte.body);
|
|
677
|
+
// Column-list results are already a dedicated object. A body query
|
|
678
|
+
// result is shared with the entity set, so dialects may copy it.
|
|
679
|
+
const outward = fromColumnList !== null && fromColumnList !== void 0 ? fromColumnList : (found ? this.adaptOutwardQueryResult(found) : null);
|
|
680
|
+
cte.outward = outward;
|
|
681
|
+
if (outward) {
|
|
682
|
+
cte.entity.relatedEntities = [outward];
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* CTE outward schema defaults to the body query result itself.
|
|
688
|
+
* Override when that result's text covers more than the select list.
|
|
689
|
+
*/
|
|
690
|
+
adaptOutwardQueryResult(entity) {
|
|
691
|
+
return entity;
|
|
692
|
+
}
|
|
693
|
+
sourceSlice(startIndex, endIndex) {
|
|
694
|
+
return this._input.slice(startIndex, endIndex + 1);
|
|
695
|
+
}
|
|
696
|
+
findOutwardQueryResult(body) {
|
|
697
|
+
var _a, _b, _c, _d;
|
|
698
|
+
if (!(body === null || body === void 0 ? void 0 : body.start) || !body.stop)
|
|
699
|
+
return null;
|
|
700
|
+
const start = body.start.tokenIndex;
|
|
701
|
+
const stop = body.stop.tokenIndex;
|
|
702
|
+
let best = null;
|
|
703
|
+
for (const entity of this._entitiesSet) {
|
|
704
|
+
if (entity.entityContextType !== EntityContextType.QUERY_RESULT ||
|
|
705
|
+
!isCommonEntityContext(entity)) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
const tokenStart = entity.position.startTokenIndex;
|
|
709
|
+
const tokenStop = entity.position.endTokenIndex;
|
|
710
|
+
if (tokenStart < start || tokenStop > stop)
|
|
711
|
+
continue;
|
|
712
|
+
if (!best) {
|
|
713
|
+
best = entity;
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
const bestDepth = (_b = (_a = best.belongStmt) === null || _a === void 0 ? void 0 : _a.scopeDepth) !== null && _b !== void 0 ? _b : 0;
|
|
717
|
+
const depth = (_d = (_c = entity.belongStmt) === null || _c === void 0 ? void 0 : _c.scopeDepth) !== null && _d !== void 0 ? _d : 0;
|
|
718
|
+
if (depth < bestDepth ||
|
|
719
|
+
(depth === bestDepth && tokenStart < best.position.startTokenIndex)) {
|
|
720
|
+
best = entity;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return best;
|
|
724
|
+
}
|
|
725
|
+
columnTokens(listCtx) {
|
|
726
|
+
const tokens = [];
|
|
727
|
+
const skip = new Set(['(', ')', ',', '.', '[', ']']);
|
|
728
|
+
const visit = (ctx) => {
|
|
729
|
+
var _a;
|
|
730
|
+
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
731
|
+
const child = ctx.getChild(i);
|
|
732
|
+
if (child instanceof ParserRuleContext) {
|
|
733
|
+
visit(child);
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (child instanceof TerminalNode) {
|
|
737
|
+
const text = (_a = child.symbol.text) !== null && _a !== void 0 ? _a : '';
|
|
738
|
+
if (text && !skip.has(text))
|
|
739
|
+
tokens.push(child.symbol);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
visit(listCtx);
|
|
744
|
+
return tokens;
|
|
745
|
+
}
|
|
746
|
+
createColumnListQueryResultFromTokens(belongStmt, tokens) {
|
|
747
|
+
const columns = [];
|
|
748
|
+
tokens.forEach((token) => {
|
|
749
|
+
const word = tokenToWord(token, this._input);
|
|
750
|
+
if (!word.text.trim())
|
|
751
|
+
return;
|
|
752
|
+
columns.push({
|
|
753
|
+
entityContextType: EntityContextType.COLUMN,
|
|
754
|
+
text: word.text,
|
|
755
|
+
position: {
|
|
756
|
+
startIndex: word.startIndex,
|
|
757
|
+
endIndex: word.endIndex,
|
|
758
|
+
line: word.line,
|
|
759
|
+
startColumn: word.startColumn,
|
|
760
|
+
endColumn: word.endColumn,
|
|
761
|
+
startTokenIndex: token.tokenIndex,
|
|
762
|
+
endTokenIndex: token.tokenIndex,
|
|
763
|
+
},
|
|
764
|
+
belongStmt,
|
|
765
|
+
declareType: ColumnDeclareType.LITERAL,
|
|
766
|
+
relatedEntities: null,
|
|
767
|
+
[AttrName.colType]: null,
|
|
768
|
+
[AttrName.comment]: null,
|
|
769
|
+
isAccessible: null,
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
return this.wrapOutwardColumns(belongStmt, columns);
|
|
773
|
+
}
|
|
774
|
+
createColumnListQueryResult(belongStmt, columnNameCtxs) {
|
|
775
|
+
const columns = [];
|
|
776
|
+
columnNameCtxs.forEach((nameCtx) => {
|
|
777
|
+
const column = toEntityContext(nameCtx, EntityContextType.COLUMN, this._input, belongStmt, undefined, { declareType: ColumnDeclareType.LITERAL });
|
|
778
|
+
if (column && isColumnEntityContext(column) && column.text.trim()) {
|
|
779
|
+
columns.push(column);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
return this.wrapOutwardColumns(belongStmt, columns);
|
|
783
|
+
}
|
|
784
|
+
wrapOutwardColumns(belongStmt, columns) {
|
|
785
|
+
if (!columns.length)
|
|
786
|
+
return null;
|
|
787
|
+
const first = columns[0].position;
|
|
788
|
+
const last = columns[columns.length - 1].position;
|
|
789
|
+
return {
|
|
790
|
+
entityContextType: EntityContextType.QUERY_RESULT,
|
|
791
|
+
text: columns.map((column) => column.text).join(', '),
|
|
792
|
+
position: {
|
|
793
|
+
startIndex: first.startIndex,
|
|
794
|
+
endIndex: last.endIndex,
|
|
795
|
+
line: first.line,
|
|
796
|
+
startColumn: first.startColumn,
|
|
797
|
+
endColumn: last.endColumn,
|
|
798
|
+
startTokenIndex: first.startTokenIndex,
|
|
799
|
+
endTokenIndex: last.endTokenIndex,
|
|
800
|
+
},
|
|
801
|
+
belongStmt,
|
|
802
|
+
relatedEntities: null,
|
|
803
|
+
columns,
|
|
804
|
+
[AttrName.comment]: null,
|
|
805
|
+
isAccessible: null,
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
bindCteReferences() {
|
|
809
|
+
this._entitiesSet.forEach((entity) => {
|
|
810
|
+
if (entity.entityContextType !== EntityContextType.TABLE ||
|
|
811
|
+
!isCommonEntityContext(entity) ||
|
|
812
|
+
entity.declareType !== TableDeclareType.LITERAL) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
const cte = this.resolveCte(entity.text, entity.position.startTokenIndex);
|
|
816
|
+
if (!cte)
|
|
817
|
+
return;
|
|
818
|
+
entity.declareType = TableDeclareType.EXPRESSION;
|
|
819
|
+
entity.relatedEntities = cte.outward ? [cte.outward] : null;
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
markCteAccessibility() {
|
|
823
|
+
const caretTokenIndex = this.getPrevNonHiddenTokenIndex(this._caretTokenIndex);
|
|
824
|
+
if (!Number.isFinite(caretTokenIndex)) {
|
|
825
|
+
this._cteDefinitions.forEach((cte) => {
|
|
826
|
+
cte.entity.isAccessible = false;
|
|
827
|
+
});
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
this._cteDefinitions.forEach((cte) => {
|
|
831
|
+
cte.entity.isAccessible = this.resolveCte(cte.name, caretTokenIndex) === cte;
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
/** Nearest preceding CTE whose scope covers `tokenIndex`. */
|
|
835
|
+
resolveCte(name, tokenIndex) {
|
|
836
|
+
let winner = null;
|
|
837
|
+
this._cteDefinitions.forEach((cte) => {
|
|
838
|
+
if (!sameIdent(cte.name, name))
|
|
839
|
+
return;
|
|
840
|
+
if (tokenIndex <= cte.endTokenIndex)
|
|
841
|
+
return;
|
|
842
|
+
if (tokenIndex > cte.scopeEndTokenIndex)
|
|
843
|
+
return;
|
|
844
|
+
if (!winner || cte.endTokenIndex > winner.endTokenIndex)
|
|
845
|
+
winner = cte;
|
|
846
|
+
});
|
|
847
|
+
return winner;
|
|
848
|
+
}
|
|
548
849
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AtomExpressionTableContext, AtomFunctionTableContext, CatalogPathContext, CatalogPathCreateContext, ColumnNameCreateContext, CreateCatalogContext, CreateDatabaseContext, CreateFunctionContext, CreateTableContext, CreateViewContext, DatabasePathContext, DatabasePathCreateContext, FunctionNameCreateContext, InsertStatementContext, QueryStatementContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SelectWindowItemColumnNameContext, SqlStatementContext, TableAllColumnsContext, TablePathContext, TablePathCreateContext, ViewPathContext, ViewPathCreateContext } from '../../lib/flink/FlinkSqlParser';
|
|
1
|
+
import { AtomExpressionTableContext, AtomFunctionTableContext, CatalogPathContext, CatalogPathCreateContext, ColumnNameCreateContext, CreateCatalogContext, CreateDatabaseContext, CreateFunctionContext, CreateTableContext, CreateViewContext, DatabasePathContext, DatabasePathCreateContext, FunctionNameCreateContext, InsertStatementContext, QueryStatementContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SelectWindowItemColumnNameContext, SqlStatementContext, TableAllColumnsContext, TablePathContext, TablePathCreateContext, ViewPathContext, ViewPathCreateContext, WithItemContext } from '../../lib/flink/FlinkSqlParser';
|
|
2
2
|
import { FlinkSqlParserListener } from '../../lib/flink/FlinkSqlParserListener';
|
|
3
3
|
import { EntityCollector } from '../common/entityCollector';
|
|
4
4
|
export declare class FlinkEntityCollector extends EntityCollector implements FlinkSqlParserListener {
|
|
@@ -11,6 +11,7 @@ export declare class FlinkEntityCollector extends EntityCollector implements Fli
|
|
|
11
11
|
exitAtomFunctionTable(ctx: AtomFunctionTableContext): void;
|
|
12
12
|
exitAtomExpressionTable(ctx: AtomExpressionTableContext): void;
|
|
13
13
|
exitTablePathCreate(ctx: TablePathCreateContext): void;
|
|
14
|
+
exitWithItem(ctx: WithItemContext): void;
|
|
14
15
|
exitViewPath(ctx: ViewPathContext): void;
|
|
15
16
|
exitViewPathCreate(ctx: ViewPathCreateContext): void;
|
|
16
17
|
exitFunctionNameCreate(ctx: FunctionNameCreateContext): void;
|
|
@@ -58,6 +58,10 @@ export class FlinkEntityCollector extends EntityCollector {
|
|
|
58
58
|
},
|
|
59
59
|
]);
|
|
60
60
|
}
|
|
61
|
+
exitWithItem(ctx) {
|
|
62
|
+
var _a, _b;
|
|
63
|
+
this.collectCte(ctx, ctx.identifier(), ctx.queryStatement(), (_b = (_a = ctx.stop) === null || _a === void 0 ? void 0 : _a.tokenIndex) !== null && _b !== void 0 ? _b : -1, ctx.columnName());
|
|
64
|
+
}
|
|
61
65
|
exitViewPath(ctx) {
|
|
62
66
|
this.pushEntity(ctx, EntityContextType.VIEW);
|
|
63
67
|
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import type { GenericSqlListener } from '../../lib/generic/GenericSqlListener';
|
|
2
|
-
import { AlterTableContext, ColumnDefinitionContext, ColumnRefContext, CreateTableContext, DeleteContext, DropTableContext, InsertContext, QuerySpecificationContext, QueryStatementContext, SelectItemContext, SingleStatementContext, TableNameContext, TableNameCreateContext, UpdateContext } from '../../lib/generic/GenericSqlParser';
|
|
3
|
-
import { EntityCollector } from '../common/entityCollector';
|
|
2
|
+
import { AlterTableContext, ColumnDefinitionContext, ColumnRefContext, CreateTableContext, DeleteContext, DropTableContext, InsertContext, NamedQueryContext, QuerySpecificationContext, QueryStatementContext, SelectItemContext, SingleStatementContext, TableNameContext, TableNameCreateContext, UpdateContext } from '../../lib/generic/GenericSqlParser';
|
|
3
|
+
import { CommonEntityContext, EntityCollector } from '../common/entityCollector';
|
|
4
4
|
export declare class GenericEntityCollector extends EntityCollector implements GenericSqlListener {
|
|
5
|
+
/** Select-list source text for each query result. The result itself keeps the full statement. */
|
|
6
|
+
private readonly selectListText;
|
|
7
|
+
enterProgram(): void;
|
|
5
8
|
/** ====== Entity Begin */
|
|
6
9
|
exitTableName(ctx: TableNameContext): void;
|
|
10
|
+
exitNamedQuery(ctx: NamedQueryContext): void;
|
|
7
11
|
exitTableNameCreate(ctx: TableNameCreateContext): void;
|
|
8
12
|
exitColumnRef(ctx: ColumnRefContext): void;
|
|
9
13
|
exitColumnDefinition(ctx: ColumnDefinitionContext): void;
|
|
10
14
|
exitQuerySpecification(ctx: QuerySpecificationContext): void;
|
|
15
|
+
protected adaptOutwardQueryResult(entity: CommonEntityContext): CommonEntityContext;
|
|
11
16
|
exitSelectItem(ctx: SelectItemContext): void;
|
|
12
17
|
private isSimpleColumnReference;
|
|
13
18
|
/** ===== Statement begin */
|
|
@@ -1,13 +1,32 @@
|
|
|
1
|
-
import { ColumnDefinitionContext,
|
|
2
|
-
import { AttrName, ColumnDeclareType, EntityCollector, StmtContextType, TableDeclareType, } from '../common/entityCollector';
|
|
1
|
+
import { ColumnDefinitionContext, AliasedRelationContext, CreateTableStatementContext, } from '../../lib/generic/GenericSqlParser';
|
|
2
|
+
import { AttrName, ColumnDeclareType, EntityCollector, isColumnEntityContext, isCommonEntityContext, StmtContextType, TableDeclareType, } from '../common/entityCollector';
|
|
3
3
|
import { EntityContextType } from '../common/types';
|
|
4
|
+
import { tokenToWord } from '../common/textAndWord';
|
|
4
5
|
export class GenericEntityCollector extends EntityCollector {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
/** Select-list source text for each query result. The result itself keeps the full statement. */
|
|
9
|
+
this.selectListText = new Map();
|
|
10
|
+
}
|
|
11
|
+
enterProgram() {
|
|
12
|
+
this.selectListText.clear();
|
|
13
|
+
super.enterProgram();
|
|
14
|
+
}
|
|
5
15
|
/** ====== Entity Begin */
|
|
6
16
|
exitTableName(ctx) {
|
|
7
|
-
this.pushEntity(ctx, EntityContextType.TABLE, [
|
|
17
|
+
this.pushEntity(ctx, EntityContextType.TABLE, [
|
|
18
|
+
{
|
|
19
|
+
attrName: AttrName.alias,
|
|
20
|
+
endContextList: [AliasedRelationContext.name],
|
|
21
|
+
},
|
|
22
|
+
], {
|
|
8
23
|
declareType: TableDeclareType.LITERAL,
|
|
9
24
|
});
|
|
10
25
|
}
|
|
26
|
+
exitNamedQuery(ctx) {
|
|
27
|
+
var _a, _b;
|
|
28
|
+
this.collectCte(ctx, ctx.identifier(), ctx.queryStatement(), (_b = (_a = ctx.stop) === null || _a === void 0 ? void 0 : _a.tokenIndex) !== null && _b !== void 0 ? _b : -1, [], ctx.cteColumnList());
|
|
29
|
+
}
|
|
11
30
|
exitTableNameCreate(ctx) {
|
|
12
31
|
this.pushEntity(ctx, EntityContextType.TABLE_CREATE, [
|
|
13
32
|
{
|
|
@@ -20,21 +39,51 @@ export class GenericEntityCollector extends EntityCollector {
|
|
|
20
39
|
this.pushEntity(ctx, EntityContextType.COLUMN);
|
|
21
40
|
}
|
|
22
41
|
exitColumnDefinition(ctx) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
42
|
+
var _a, _b;
|
|
43
|
+
// The name is only `columnRef`. Pushing the whole definition made the
|
|
44
|
+
// completion label `age int` and inserted the type into the SQL.
|
|
45
|
+
const entity = this.pushEntity(ctx.columnRef(), EntityContextType.COLUMN_CREATE, [
|
|
28
46
|
{
|
|
29
47
|
attrName: AttrName.comment,
|
|
30
48
|
endContextList: [ColumnDefinitionContext.name],
|
|
31
49
|
},
|
|
32
50
|
]);
|
|
51
|
+
const dataType = ctx.dataType();
|
|
52
|
+
if (entity && isColumnEntityContext(entity) && (dataType === null || dataType === void 0 ? void 0 : dataType.start) && dataType.stop) {
|
|
53
|
+
const startIndex = dataType.start.start;
|
|
54
|
+
const endIndex = dataType.stop.stop;
|
|
55
|
+
const typeText = this.sourceSlice(startIndex, endIndex);
|
|
56
|
+
const startColumn = dataType.start.column + 1;
|
|
57
|
+
entity[AttrName.colType] = {
|
|
58
|
+
text: typeText,
|
|
59
|
+
line: dataType.start.line,
|
|
60
|
+
startIndex,
|
|
61
|
+
endIndex,
|
|
62
|
+
startColumn,
|
|
63
|
+
endColumn: dataType.stop.line === dataType.start.line
|
|
64
|
+
? startColumn + typeText.length
|
|
65
|
+
: dataType.stop.column + 1 + ((_b = (_a = dataType.stop.text) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
33
68
|
}
|
|
34
69
|
exitQuerySpecification(ctx) {
|
|
35
|
-
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const entity = this.pushEntity(ctx, EntityContextType.QUERY_RESULT);
|
|
72
|
+
const items = ctx.selectItem();
|
|
73
|
+
const first = (_a = items[0]) === null || _a === void 0 ? void 0 : _a.start;
|
|
74
|
+
const last = (_b = items[items.length - 1]) === null || _b === void 0 ? void 0 : _b.stop;
|
|
75
|
+
if (entity && isCommonEntityContext(entity) && first && last) {
|
|
76
|
+
this.selectListText.set(entity, this.sourceSlice(first.start, last.stop));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
adaptOutwardQueryResult(entity) {
|
|
80
|
+
const text = this.selectListText.get(entity);
|
|
81
|
+
if (text == null)
|
|
82
|
+
return entity;
|
|
83
|
+
return Object.assign(Object.assign({}, entity), { text });
|
|
36
84
|
}
|
|
37
85
|
exitSelectItem(ctx) {
|
|
86
|
+
var _a;
|
|
38
87
|
if (ctx.ASTERISK()) {
|
|
39
88
|
this.pushEntity(ctx, EntityContextType.COLUMN, [], {
|
|
40
89
|
declareType: ColumnDeclareType.ALL,
|
|
@@ -42,16 +91,17 @@ export class GenericEntityCollector extends EntityCollector {
|
|
|
42
91
|
}
|
|
43
92
|
else {
|
|
44
93
|
const isSimpleColumn = this.isSimpleColumnReference(ctx);
|
|
45
|
-
this.pushEntity(ctx, EntityContextType.COLUMN, [
|
|
46
|
-
{
|
|
47
|
-
attrName: AttrName.alias,
|
|
48
|
-
endContextList: [SelectItemContext.name],
|
|
49
|
-
},
|
|
50
|
-
], {
|
|
94
|
+
const entity = this.pushEntity(ctx, EntityContextType.COLUMN, [], {
|
|
51
95
|
declareType: isSimpleColumn
|
|
52
96
|
? ColumnDeclareType.LITERAL
|
|
53
97
|
: ColumnDeclareType.EXPRESSION,
|
|
54
98
|
});
|
|
99
|
+
// The alias sits on this select item. Searching parents would pick a
|
|
100
|
+
// later item's alias and label every column with that name.
|
|
101
|
+
const aliasToken = (_a = ctx._alias) === null || _a === void 0 ? void 0 : _a.start;
|
|
102
|
+
if (entity && aliasToken) {
|
|
103
|
+
entity[AttrName.alias] = tokenToWord(aliasToken, '');
|
|
104
|
+
}
|
|
55
105
|
}
|
|
56
106
|
}
|
|
57
107
|
isSimpleColumnReference(ctx) {
|
|
@@ -19,6 +19,7 @@ export class GenericSQL extends BasicSQL {
|
|
|
19
19
|
GenericSqlParser.RULE_tableName,
|
|
20
20
|
GenericSqlParser.RULE_tableNameCreate,
|
|
21
21
|
GenericSqlParser.RULE_columnRef,
|
|
22
|
+
GenericSqlParser.RULE_qualifiedName,
|
|
22
23
|
...this.excludeKeywordRules,
|
|
23
24
|
]);
|
|
24
25
|
this._diagnostics = (options === null || options === void 0 ? void 0 : options.diagnostics) !== false;
|
|
@@ -68,6 +69,17 @@ export class GenericSQL extends BasicSQL {
|
|
|
68
69
|
syntaxContextType = EntityContextType.COLUMN;
|
|
69
70
|
break;
|
|
70
71
|
}
|
|
72
|
+
case GenericSqlParser.RULE_qualifiedName: {
|
|
73
|
+
// Expressions use qualifiedName for columns. Table names use the same
|
|
74
|
+
// rule through tableName, and those stay TABLE suggestions.
|
|
75
|
+
const rules = candidateRule.ruleList;
|
|
76
|
+
if (!rules.includes(GenericSqlParser.RULE_tableName) &&
|
|
77
|
+
!rules.includes(GenericSqlParser.RULE_tableNameCreate) &&
|
|
78
|
+
rules.includes(GenericSqlParser.RULE_expression)) {
|
|
79
|
+
syntaxContextType = EntityContextType.COLUMN;
|
|
80
|
+
}
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
71
83
|
default:
|
|
72
84
|
break;
|
|
73
85
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HiveSqlParserListener } from '../../lib';
|
|
2
|
-
import { AtomPartitionedTableFunctionContext, AtomValuesClauseContext, ColumnNameCreateContext, CreateDatabaseStatementContext, CreateFunctionStatementContext, CreateMaterializedViewStatementContext, CreateTableStatementContext, CreateViewStatementContext, DbSchemaNameContext, DbSchemaNameCreateContext, FromInsertStmtContext, FromSelectStmtContext, FunctionNameCreateContext, InsertStmtContext, QueryStatementExpressionContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SelectStatementContext, StatementContext, TableAllColumnsContext, TableNameContext, TableNameCreateContext, ViewNameContext, ViewNameCreateContext } from '../../lib/hive/HiveSqlParser';
|
|
2
|
+
import { AtomPartitionedTableFunctionContext, AtomValuesClauseContext, ColumnNameCreateContext, CreateDatabaseStatementContext, CreateFunctionStatementContext, CreateMaterializedViewStatementContext, CreateTableStatementContext, CreateViewStatementContext, CteStatementContext, DbSchemaNameContext, DbSchemaNameCreateContext, FromInsertStmtContext, FromSelectStmtContext, FunctionNameCreateContext, InsertStmtContext, QueryStatementExpressionContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SelectStatementContext, StatementContext, TableAllColumnsContext, TableNameContext, TableNameCreateContext, ViewNameContext, ViewNameCreateContext } from '../../lib/hive/HiveSqlParser';
|
|
3
3
|
import { EntityCollector } from '../common/entityCollector';
|
|
4
4
|
export declare class HiveEntityCollector extends EntityCollector implements HiveSqlParserListener {
|
|
5
5
|
/** ====== Entity Begin */
|
|
@@ -19,6 +19,7 @@ export declare class HiveEntityCollector extends EntityCollector implements Hive
|
|
|
19
19
|
exitTableAllColumns(ctx: TableAllColumnsContext): void;
|
|
20
20
|
exitViewNameCreate(ctx: ViewNameCreateContext): void;
|
|
21
21
|
exitSelectList(ctx: SelectListContext): void;
|
|
22
|
+
exitCteStatement(ctx: CteStatementContext): void;
|
|
22
23
|
exitViewName(ctx: ViewNameContext): void;
|
|
23
24
|
exitDbSchemaNameCreate(ctx: DbSchemaNameCreateContext): void;
|
|
24
25
|
exitDbSchemaName(ctx: DbSchemaNameContext): void;
|
|
@@ -116,6 +116,11 @@ export class HiveEntityCollector extends EntityCollector {
|
|
|
116
116
|
exitSelectList(ctx) {
|
|
117
117
|
this.pushEntity(ctx, EntityContextType.QUERY_RESULT);
|
|
118
118
|
}
|
|
119
|
+
exitCteStatement(ctx) {
|
|
120
|
+
var _a, _b, _c, _d;
|
|
121
|
+
const columns = (_b = (_a = ctx.columnNameList()) === null || _a === void 0 ? void 0 : _a.columnName()) !== null && _b !== void 0 ? _b : [];
|
|
122
|
+
this.collectCte(ctx, ctx.id_(), ctx.queryStatementExpression(), (_d = (_c = ctx.stop) === null || _c === void 0 ? void 0 : _c.tokenIndex) !== null && _d !== void 0 ? _d : -1, columns);
|
|
123
|
+
}
|
|
119
124
|
exitViewName(ctx) {
|
|
120
125
|
this.pushEntity(ctx, EntityContextType.VIEW);
|
|
121
126
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ImpalaSqlParserListener } from '../../lib';
|
|
2
|
-
import { AtomSubQueryTableSourceContext, ColumnNamePathCreateContext, CreateAggregateFunctionContext, CreateFunctionContext, CreateKuduTableAsSelectContext, CreateSchemaContext, CreateTableLikeContext, CreateTableSelectContext, CreateViewContext, DatabaseNameCreateContext, DatabaseNamePathContext, FunctionNameCreateContext, InsertStatementContext, QueryStatementContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SingleStatementContext, TableAllColumnsContext, TableNameCreateContext, TableNamePathContext, UnnestContext, ViewNameCreateContext, ViewNamePathContext } from '../../lib/impala/ImpalaSqlParser';
|
|
2
|
+
import { AtomSubQueryTableSourceContext, ColumnNamePathCreateContext, CreateAggregateFunctionContext, CreateFunctionContext, CreateKuduTableAsSelectContext, CreateSchemaContext, CreateTableLikeContext, CreateTableSelectContext, CreateViewContext, DatabaseNameCreateContext, DatabaseNamePathContext, FunctionNameCreateContext, InsertStatementContext, NamedQueryContext, QueryStatementContext, SelectExpressionColumnNameContext, SelectListContext, SelectLiteralColumnNameContext, SingleStatementContext, TableAllColumnsContext, TableNameCreateContext, TableNamePathContext, UnnestContext, ViewNameCreateContext, ViewNamePathContext } from '../../lib/impala/ImpalaSqlParser';
|
|
3
3
|
import { EntityCollector } from '../common/entityCollector';
|
|
4
4
|
export declare class ImpalaEntityCollector extends EntityCollector implements ImpalaSqlParserListener {
|
|
5
5
|
/** ===== Entity begin */
|
|
@@ -9,6 +9,7 @@ export declare class ImpalaEntityCollector extends EntityCollector implements Im
|
|
|
9
9
|
exitUnnest(ctx: UnnestContext): void;
|
|
10
10
|
exitColumnNamePathCreate(ctx: ColumnNamePathCreateContext): void;
|
|
11
11
|
exitViewNameCreate(ctx: ViewNameCreateContext): void;
|
|
12
|
+
exitNamedQuery(ctx: NamedQueryContext): void;
|
|
12
13
|
exitViewNamePath(ctx: ViewNamePathContext): void;
|
|
13
14
|
exitDatabaseNamePath(ctx: DatabaseNamePathContext): void;
|
|
14
15
|
exitDatabaseNameCreate(ctx: DatabaseNameCreateContext): void;
|
|
@@ -72,6 +72,10 @@ export class ImpalaEntityCollector extends EntityCollector {
|
|
|
72
72
|
},
|
|
73
73
|
]);
|
|
74
74
|
}
|
|
75
|
+
exitNamedQuery(ctx) {
|
|
76
|
+
var _a, _b;
|
|
77
|
+
this.collectCte(ctx, ctx.identifier(), ctx.subQueryRelation(), (_b = (_a = ctx.stop) === null || _a === void 0 ? void 0 : _a.tokenIndex) !== null && _b !== void 0 ? _b : -1, [], ctx.columnAliases());
|
|
78
|
+
}
|
|
75
79
|
exitViewNamePath(ctx) {
|
|
76
80
|
this.pushEntity(ctx, EntityContextType.VIEW);
|
|
77
81
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColumnCreateTableContext, ColumnNameCreateContext, CopyCreateTableContext, CreateDatabaseContext, CreateFunctionContext, CreateFunctionLoadableContext, CreateViewContext, DatabaseNameContext, DatabaseNameCreateContext, FunctionNameCreateContext, InsertStatementContext, QueryCreateTableContext, SelectElementsContext, SelectExpressionElementContext, SelectLiteralColumnNameContext, SelectStatementContext, SingleStatementContext, TableNameContext, TableNameCreateContext, ViewNameContext, ViewNameCreateContext, TableAllColumnsContext, AtomSubQueryTableSourceContext, PureAllColumnsContext, SelectElement_dot_emptyContext, ColumnNamePath_dot_emptyContext } from '../../lib/mysql/MySqlParser';
|
|
1
|
+
import { ColumnCreateTableContext, ColumnNameCreateContext, CopyCreateTableContext, CreateDatabaseContext, CreateFunctionContext, CreateFunctionLoadableContext, CreateViewContext, DatabaseNameContext, DatabaseNameCreateContext, FunctionNameCreateContext, InsertStatementContext, QueryCreateTableContext, SelectElementsContext, SelectExpressionElementContext, SelectLiteralColumnNameContext, SelectStatementContext, SingleStatementContext, TableNameContext, TableNameCreateContext, ViewNameContext, ViewNameCreateContext, TableAllColumnsContext, AtomSubQueryTableSourceContext, CommonTableExpressionsContext, PureAllColumnsContext, SelectElement_dot_emptyContext, ColumnNamePath_dot_emptyContext } from '../../lib/mysql/MySqlParser';
|
|
2
2
|
import type { MySqlParserListener } from '../../lib/mysql/MySqlParserListener';
|
|
3
3
|
import { EntityCollector } from '../common/entityCollector';
|
|
4
4
|
export declare class MySqlEntityCollector extends EntityCollector implements MySqlParserListener {
|
|
@@ -7,6 +7,7 @@ export declare class MySqlEntityCollector extends EntityCollector implements MyS
|
|
|
7
7
|
exitDatabaseNameCreate(ctx: DatabaseNameCreateContext): void;
|
|
8
8
|
/** Table Entity Rules */
|
|
9
9
|
exitTableName(ctx: TableNameContext): void;
|
|
10
|
+
exitCommonTableExpressions(ctx: CommonTableExpressionsContext): void;
|
|
10
11
|
/** SubQuery Table Entity Rules */
|
|
11
12
|
exitAtomSubQueryTableSource(ctx: AtomSubQueryTableSourceContext): void;
|
|
12
13
|
exitTableNameCreate(ctx: TableNameCreateContext): void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TerminalNode } from 'antlr4ng';
|
|
1
2
|
import { ColumnCreateTableContext, CreateDefinitionContext, CreateFunctionContext, TableSourceItemContext, AtomTableItemContext, SubqueryTableItemContext, SelectElement_labelContext, SelectElement_exprContext, } from '../../lib/mysql/MySqlParser';
|
|
2
3
|
import { AttrName, ColumnDeclareType, EntityCollector, StmtContextType, TableDeclareType, } from '../common/entityCollector';
|
|
3
4
|
import { EntityContextType } from '../common/types';
|
|
@@ -20,6 +21,24 @@ export class MySqlEntityCollector extends EntityCollector {
|
|
|
20
21
|
declareType: TableDeclareType.LITERAL,
|
|
21
22
|
});
|
|
22
23
|
}
|
|
24
|
+
exitCommonTableExpressions(ctx) {
|
|
25
|
+
var _a, _b, _c;
|
|
26
|
+
const names = ctx.uid();
|
|
27
|
+
if (!(names === null || names === void 0 ? void 0 : names.length))
|
|
28
|
+
return;
|
|
29
|
+
const bodyEnd = (_c = (_b = (_a = ctx.dmlStatement()) === null || _a === void 0 ? void 0 : _a.stop) === null || _b === void 0 ? void 0 : _b.tokenIndex) !== null && _c !== void 0 ? _c : -1;
|
|
30
|
+
let endTokenIndex = bodyEnd;
|
|
31
|
+
for (let i = 0; i < ctx.getChildCount(); i++) {
|
|
32
|
+
const child = ctx.getChild(i);
|
|
33
|
+
if (!(child instanceof TerminalNode))
|
|
34
|
+
continue;
|
|
35
|
+
if (child.symbol.text === ')' && child.symbol.tokenIndex > bodyEnd) {
|
|
36
|
+
endTokenIndex = child.symbol.tokenIndex;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this.collectCte(ctx, names[0], ctx.dmlStatement(), endTokenIndex, names.slice(1));
|
|
41
|
+
}
|
|
23
42
|
/** SubQuery Table Entity Rules */
|
|
24
43
|
exitAtomSubQueryTableSource(ctx) {
|
|
25
44
|
this.pushEntity(ctx, EntityContextType.TABLE, [
|