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.
Files changed (48) hide show
  1. package/dist/lib/flink/FlinkSqlParser.d.ts +220 -363
  2. package/dist/lib/flink/FlinkSqlParser.js +3246 -4046
  3. package/dist/lib/flink/FlinkSqlParserListener.d.ts +0 -154
  4. package/dist/lib/flink/FlinkSqlParserVisitor.d.ts +0 -98
  5. package/dist/lib/generic/GenericSqlListener.d.ts +11 -0
  6. package/dist/lib/generic/GenericSqlParser.d.ts +61 -47
  7. package/dist/lib/generic/GenericSqlParser.js +1047 -949
  8. package/dist/lib/generic/GenericSqlVisitor.d.ts +7 -0
  9. package/dist/lib/hive/HiveSqlParser.d.ts +515 -943
  10. package/dist/lib/hive/HiveSqlParser.js +8234 -10573
  11. package/dist/lib/hive/HiveSqlParserListener.d.ts +50 -490
  12. package/dist/lib/hive/HiveSqlParserVisitor.d.ts +30 -310
  13. package/dist/lib/impala/ImpalaSqlParser.d.ts +96 -131
  14. package/dist/lib/impala/ImpalaSqlParser.js +3311 -3522
  15. package/dist/lib/impala/ImpalaSqlParserListener.d.ts +0 -44
  16. package/dist/lib/impala/ImpalaSqlParserVisitor.d.ts +0 -28
  17. package/dist/lib/mysql/MySqlParser.d.ts +425 -465
  18. package/dist/lib/mysql/MySqlParser.js +10300 -10510
  19. package/dist/lib/mysql/MySqlParserListener.d.ts +0 -44
  20. package/dist/lib/mysql/MySqlParserVisitor.d.ts +0 -28
  21. package/dist/lib/postgresql/PostgreSqlParser.d.ts +181 -164
  22. package/dist/lib/postgresql/PostgreSqlParser.js +10273 -10121
  23. package/dist/lib/postgresql/PostgreSqlParserListener.d.ts +11 -0
  24. package/dist/lib/postgresql/PostgreSqlParserVisitor.d.ts +7 -0
  25. package/dist/lib/trino/TrinoSqlListener.d.ts +0 -328
  26. package/dist/lib/trino/TrinoSqlParser.d.ts +205 -477
  27. package/dist/lib/trino/TrinoSqlParser.js +6689 -7898
  28. package/dist/lib/trino/TrinoSqlVisitor.d.ts +0 -206
  29. package/dist/parser/common/entityCollector.d.ts +37 -2
  30. package/dist/parser/common/entityCollector.js +303 -2
  31. package/dist/parser/flink/flinkEntityCollector.d.ts +2 -1
  32. package/dist/parser/flink/flinkEntityCollector.js +4 -0
  33. package/dist/parser/generic/genericEntityCollector.d.ts +7 -2
  34. package/dist/parser/generic/genericEntityCollector.js +65 -15
  35. package/dist/parser/generic/index.js +12 -0
  36. package/dist/parser/hive/hiveEntityCollector.d.ts +2 -1
  37. package/dist/parser/hive/hiveEntityCollector.js +5 -0
  38. package/dist/parser/impala/impalaEntityCollector.d.ts +2 -1
  39. package/dist/parser/impala/impalaEntityCollector.js +4 -0
  40. package/dist/parser/mysql/mysqlEntityCollector.d.ts +2 -1
  41. package/dist/parser/mysql/mysqlEntityCollector.js +19 -0
  42. package/dist/parser/postgresql/postgreEntityCollector.d.ts +2 -1
  43. package/dist/parser/postgresql/postgreEntityCollector.js +5 -0
  44. package/dist/parser/spark/sparkEntityCollector.d.ts +2 -1
  45. package/dist/parser/spark/sparkEntityCollector.js +5 -0
  46. package/dist/parser/trino/trinoEntityCollector.d.ts +2 -1
  47. package/dist/parser/trino/trinoEntityCollector.js +5 -0
  48. 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, CreateTableStatementContext, SelectItemContext, } from '../../lib/generic/GenericSqlParser';
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
- this.pushEntity(ctx, EntityContextType.COLUMN_CREATE, [
24
- {
25
- attrName: AttrName.colType,
26
- endContextList: [ColumnDefinitionContext.name],
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
- this.pushEntity(ctx, EntityContextType.QUERY_RESULT);
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, [