dt-sql-parser 4.5.0-beta.2 → 4.5.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.
Files changed (49) hide show
  1. package/README.md +2 -1
  2. package/dist/lib/SQLParserBase.d.ts +13 -1
  3. package/dist/lib/SQLParserBase.js +40 -5
  4. package/dist/lib/flink/FlinkSqlLexer.d.ts +399 -397
  5. package/dist/lib/flink/FlinkSqlLexer.js +2504 -2489
  6. package/dist/lib/flink/FlinkSqlParser.d.ts +773 -578
  7. package/dist/lib/flink/FlinkSqlParser.js +5657 -3651
  8. package/dist/lib/flink/FlinkSqlParserListener.d.ts +123 -0
  9. package/dist/lib/flink/FlinkSqlParserVisitor.d.ts +78 -0
  10. package/dist/lib/hive/HiveSqlParser.d.ts +274 -228
  11. package/dist/lib/hive/HiveSqlParser.js +6304 -5912
  12. package/dist/lib/hive/HiveSqlParserListener.d.ts +33 -0
  13. package/dist/lib/hive/HiveSqlParserVisitor.d.ts +21 -0
  14. package/dist/lib/impala/ImpalaSqlParser.d.ts +145 -103
  15. package/dist/lib/impala/ImpalaSqlParser.js +3687 -3320
  16. package/dist/lib/impala/ImpalaSqlParserListener.d.ts +33 -0
  17. package/dist/lib/impala/ImpalaSqlParserVisitor.d.ts +21 -0
  18. package/dist/lib/mysql/MySqlParser.d.ts +161 -94
  19. package/dist/lib/mysql/MySqlParser.js +9959 -9499
  20. package/dist/lib/mysql/MySqlParserListener.d.ts +79 -5
  21. package/dist/lib/mysql/MySqlParserVisitor.d.ts +49 -3
  22. package/dist/lib/postgresql/PostgreSqlParser.d.ts +108 -71
  23. package/dist/lib/postgresql/PostgreSqlParser.js +13330 -10388
  24. package/dist/lib/postgresql/PostgreSqlParserListener.d.ts +48 -0
  25. package/dist/lib/postgresql/PostgreSqlParserVisitor.d.ts +30 -0
  26. package/dist/lib/spark/SparkSqlParser.d.ts +186 -146
  27. package/dist/lib/spark/SparkSqlParser.js +5368 -5095
  28. package/dist/lib/spark/SparkSqlParserListener.d.ts +33 -0
  29. package/dist/lib/spark/SparkSqlParserVisitor.d.ts +21 -0
  30. package/dist/lib/trino/TrinoSqlLexer.d.ts +297 -296
  31. package/dist/lib/trino/TrinoSqlLexer.js +1451 -1445
  32. package/dist/lib/trino/TrinoSqlListener.d.ts +13 -0
  33. package/dist/lib/trino/TrinoSqlParser.d.ts +308 -297
  34. package/dist/lib/trino/TrinoSqlParser.js +2381 -2300
  35. package/dist/lib/trino/TrinoSqlVisitor.d.ts +8 -0
  36. package/dist/parser/common/basicSQL.d.ts +17 -5
  37. package/dist/parser/common/basicSQL.js +74 -3
  38. package/dist/parser/common/entityCollector.js +14 -2
  39. package/dist/parser/flink/index.js +5 -2
  40. package/dist/parser/generic/genericEntityCollector.d.ts +1 -0
  41. package/dist/parser/generic/genericEntityCollector.js +14 -1
  42. package/dist/parser/mysql/index.js +3 -1
  43. package/dist/parser/mysql/mysqlEntityCollector.d.ts +2 -1
  44. package/dist/parser/mysql/mysqlEntityCollector.js +13 -3
  45. package/dist/parser/mysql/mysqlErrorListener.js +2 -0
  46. package/dist/parser/postgresql/postgreEntityCollector.d.ts +3 -1
  47. package/dist/parser/postgresql/postgreEntityCollector.js +13 -0
  48. package/dist/parser/spark/index.js +3 -1
  49. package/package.json +1 -1
@@ -223,6 +223,7 @@ import { NullLiteralContext } from "./TrinoSqlParser.js";
223
223
  import { RowConstructorContext } from "./TrinoSqlParser.js";
224
224
  import { SubscriptContext } from "./TrinoSqlParser.js";
225
225
  import { JsonExistsContext } from "./TrinoSqlParser.js";
226
+ import { CoalesceContext } from "./TrinoSqlParser.js";
226
227
  import { CurrentPathContext } from "./TrinoSqlParser.js";
227
228
  import { SubqueryExpressionContext } from "./TrinoSqlParser.js";
228
229
  import { BinaryLiteralContext } from "./TrinoSqlParser.js";
@@ -1888,6 +1889,13 @@ export declare class TrinoSqlVisitor<Result> extends AbstractParseTreeVisitor<Re
1888
1889
  * @return the visitor result
1889
1890
  */
1890
1891
  visitJsonExists?: (ctx: JsonExistsContext) => Result;
1892
+ /**
1893
+ * Visit a parse tree produced by the `coalesce`
1894
+ * labeled alternative in `TrinoSqlParser.primaryExpression`.
1895
+ * @param ctx the parse tree
1896
+ * @return the visitor result
1897
+ */
1898
+ visitCoalesce?: (ctx: CoalesceContext) => Result;
1891
1899
  /**
1892
1900
  * Visit a parse tree produced by the `currentPath`
1893
1901
  * labeled alternative in `TrinoSqlParser.primaryExpression`.
@@ -1,13 +1,13 @@
1
- import { Lexer, Token, CommonTokenStream, CharStream, ParserRuleContext, ParseTreeListener, ANTLRErrorListener, Parser } from 'antlr4ng';
2
1
  import { CandidatesCollection } from 'antlr4-c3';
2
+ import { ANTLRErrorListener, CharStream, CommonTokenStream, Lexer, Parser, ParserRuleContext, ParseTreeListener, Token } from 'antlr4ng';
3
3
  import { SQLParserBase } from '../../lib/SQLParserBase';
4
- import { TextSlice } from './textAndWord';
5
- import { CaretPosition, LOCALE_TYPE, SemanticCollectOptions, Suggestions } from './types';
6
- import { ParseError, ErrorListener } from './parseErrorListener';
7
- import type { SplitListener } from './splitListener';
8
4
  import type { EntityCollector } from './entityCollector';
9
5
  import { EntityContext } from './entityCollector';
6
+ import { ErrorListener, ParseError } from './parseErrorListener';
10
7
  import SemanticContextCollector from './semanticContextCollector';
8
+ import type { SplitListener } from './splitListener';
9
+ import { TextSlice } from './textAndWord';
10
+ import { CaretPosition, LOCALE_TYPE, SemanticCollectOptions, Suggestions } from './types';
11
11
  export declare const SQL_SPLIT_SYMBOL_TEXT = ";";
12
12
  /**
13
13
  * Basic SQL class, every sql needs extends it.
@@ -95,10 +95,22 @@ export declare abstract class BasicSQL<L extends Lexer = Lexer, PRC extends Pars
95
95
  private parseWithCache;
96
96
  /**
97
97
  * Validate input string and return syntax errors if exists.
98
+ * When input contains multiple statements separated by semicolons
99
+ * and the initial parse doesn't capture all errors, each statement
100
+ * is validated independently to collect all errors.
98
101
  * @param input source string
99
102
  * @returns syntax errors
100
103
  */
101
104
  validate(input: string): ParseError[];
105
+ /**
106
+ * Validate each statement fragment independently and collect all errors.
107
+ */
108
+ private validateStatements;
109
+ /**
110
+ * Split input into individual statement strings by semicolons.
111
+ * Handles semicolons inside quoted strings correctly.
112
+ */
113
+ private splitStatements;
102
114
  /**
103
115
  * Get the input string that has been parsed.
104
116
  */
@@ -1,8 +1,8 @@
1
- import { CharStreams, CommonTokenStream, ParseTreeWalker, PredictionMode, } from 'antlr4ng';
2
1
  import { CodeCompletionCore } from 'antlr4-c3';
2
+ import { CharStreams, CommonTokenStream, ParseTreeWalker, PredictionMode, } from 'antlr4ng';
3
+ import { ErrorStrategy } from './errorStrategy';
3
4
  import { findCaretTokenIndex } from './findCaretTokenIndex';
4
5
  import { ctxToText, tokenToWord } from './textAndWord';
5
- import { ErrorStrategy } from './errorStrategy';
6
6
  export const SQL_SPLIT_SYMBOL_TEXT = ';';
7
7
  /**
8
8
  * Basic SQL class, every sql needs extends it.
@@ -104,13 +104,84 @@ export class BasicSQL {
104
104
  }
105
105
  /**
106
106
  * Validate input string and return syntax errors if exists.
107
+ * When input contains multiple statements separated by semicolons
108
+ * and the initial parse doesn't capture all errors, each statement
109
+ * is validated independently to collect all errors.
107
110
  * @param input source string
108
111
  * @returns syntax errors
109
112
  */
110
113
  validate(input) {
111
114
  this.parseWithCache(input);
115
+ if (this._parseErrors.length > 0) {
116
+ const statements = this.splitStatements(input);
117
+ if (statements.length > 1) {
118
+ const splitErrors = this.validateStatements(statements);
119
+ if (splitErrors.length > this._parseErrors.length) {
120
+ this._parseErrors = splitErrors;
121
+ }
122
+ }
123
+ }
112
124
  return this._parseErrors;
113
125
  }
126
+ /**
127
+ * Validate each statement fragment independently and collect all errors.
128
+ */
129
+ validateStatements(statements) {
130
+ const allErrors = [];
131
+ let lineOffset = 0;
132
+ for (const statement of statements) {
133
+ if (!statement.text.trim()) {
134
+ const newlines = (statement.text.match(/\n/g) || []).length;
135
+ lineOffset += newlines;
136
+ continue;
137
+ }
138
+ const parser = this.createParser(statement.text);
139
+ const errors = [];
140
+ parser.removeErrorListeners();
141
+ parser.addErrorListener(this.createErrorListener((error) => {
142
+ errors.push({
143
+ startLine: error.startLine + lineOffset,
144
+ endLine: error.endLine + lineOffset,
145
+ startColumn: error.startColumn,
146
+ endColumn: error.endColumn,
147
+ message: error.message,
148
+ });
149
+ }));
150
+ parser.errorHandler = new ErrorStrategy();
151
+ parser.program();
152
+ allErrors.push(...errors);
153
+ const newlines = (statement.text.match(/\n/g) || []).length;
154
+ lineOffset += newlines;
155
+ }
156
+ return allErrors;
157
+ }
158
+ /**
159
+ * Split input into individual statement strings by semicolons.
160
+ * Handles semicolons inside quoted strings correctly.
161
+ */
162
+ splitStatements(input) {
163
+ const statements = [];
164
+ let inSingleQuote = false;
165
+ let inDoubleQuote = false;
166
+ let lastSplit = 0;
167
+ for (let i = 0; i < input.length; i++) {
168
+ const ch = input[i];
169
+ if (ch === "'" && !inDoubleQuote) {
170
+ inSingleQuote = !inSingleQuote;
171
+ }
172
+ else if (ch === '"' && !inSingleQuote) {
173
+ inDoubleQuote = !inDoubleQuote;
174
+ }
175
+ else if (ch === ';' && !inSingleQuote && !inDoubleQuote) {
176
+ statements.push({ text: input.slice(lastSplit, i + 1), start: lastSplit });
177
+ lastSplit = i + 1;
178
+ }
179
+ }
180
+ if (lastSplit < input.length) {
181
+ statements.push({ text: input.slice(lastSplit), start: lastSplit });
182
+ }
183
+ return statements;
184
+ }
114
185
  /**
115
186
  * Get the input string that has been parsed.
116
187
  */
@@ -360,7 +431,7 @@ export class BasicSQL {
360
431
  const core = new CodeCompletionCore(sqlParserIns);
361
432
  core.preferredRules = this.preferredRules;
362
433
  // core.showRuleStack = true;
363
- // core.showResult = true;
434
+ // core.showResult = true;
364
435
  const candidates = core.collectCandidates(caretTokenIndex, parseTree);
365
436
  const originalSuggestions = this.processCandidates(candidates, allTokens, caretTokenIndex);
366
437
  const syntaxSuggestions = originalSuggestions.syntax.map((syntaxCtx) => {
@@ -436,8 +436,20 @@ export class EntityCollector {
436
436
  }
437
437
  else {
438
438
  // Do not collect column and queryResult entities if they are not inside a select statement
439
- return entitiesInsideStmt.filter((entity) => entity.entityContextType !== EntityContextType.COLUMN &&
440
- entity.entityContextType !== EntityContextType.QUERY_RESULT);
439
+ // Exception: empty column entities (text === '') should be kept
440
+ return entitiesInsideStmt.filter((entity) => {
441
+ // Keep non-COLUMN and non-QUERY_RESULT entities
442
+ if (entity.entityContextType !== EntityContextType.COLUMN &&
443
+ entity.entityContextType !== EntityContextType.QUERY_RESULT) {
444
+ return true;
445
+ }
446
+ // Also keep empty QUERY_RESULT entities (text === '')
447
+ if (entity.entityContextType === EntityContextType.QUERY_RESULT &&
448
+ entity.text === '') {
449
+ return true;
450
+ }
451
+ return false;
452
+ });
441
453
  }
442
454
  }
443
455
  combineQueryResultStmtEntities(stmtContext, entitiesInsideStmt) {
@@ -36,6 +36,7 @@ export class FlinkSQL extends BasicSQL {
36
36
  FlinkSqlParser.RULE_functionNameCreate, // functionName that will be created
37
37
  FlinkSqlParser.RULE_columnName,
38
38
  FlinkSqlParser.RULE_columnNamePath,
39
+ FlinkSqlParser.RULE_columnNamePathAllowEmpty,
39
40
  FlinkSqlParser.RULE_columnNameCreate,
40
41
  FlinkSqlParser.RULE_tablePropertyKey,
41
42
  FlinkSqlParser.RULE_tablePropertyValue,
@@ -116,13 +117,15 @@ export class FlinkSQL extends BasicSQL {
116
117
  syntaxContextType = EntityContextType.COLUMN_CREATE;
117
118
  break;
118
119
  }
119
- case FlinkSqlParser.RULE_columnNamePath: {
120
+ case FlinkSqlParser.RULE_columnNamePath:
121
+ case FlinkSqlParser.RULE_columnNamePathAllowEmpty: {
120
122
  if (candidateRule.ruleList.includes(FlinkSqlParser.RULE_selectClause) ||
121
123
  candidateRule.ruleList.includes(FlinkSqlParser.RULE_whereClause) ||
122
124
  candidateRule.ruleList.includes(FlinkSqlParser.RULE_groupByClause) ||
123
125
  candidateRule.ruleList.includes(FlinkSqlParser.RULE_limitClause) ||
124
126
  candidateRule.ruleList.includes(FlinkSqlParser.RULE_whenClause) ||
125
- candidateRule.ruleList.includes(FlinkSqlParser.RULE_havingClause)) {
127
+ candidateRule.ruleList.includes(FlinkSqlParser.RULE_havingClause) ||
128
+ candidateRule.ruleList.includes(FlinkSqlParser.RULE_joinCondition)) {
126
129
  syntaxContextType = EntityContextType.COLUMN;
127
130
  }
128
131
  break;
@@ -9,6 +9,7 @@ export declare class GenericEntityCollector extends EntityCollector implements G
9
9
  exitColumnDefinition(ctx: ColumnDefinitionContext): void;
10
10
  exitQuerySpecification(ctx: QuerySpecificationContext): void;
11
11
  exitSelectItem(ctx: SelectItemContext): void;
12
+ private isSimpleColumnReference;
12
13
  /** ===== Statement begin */
13
14
  enterSingleStatement(ctx: SingleStatementContext): void;
14
15
  exitSingleStatement(ctx: SingleStatementContext): void;
@@ -41,16 +41,29 @@ export class GenericEntityCollector extends EntityCollector {
41
41
  });
42
42
  }
43
43
  else {
44
+ const isSimpleColumn = this.isSimpleColumnReference(ctx);
44
45
  this.pushEntity(ctx, EntityContextType.COLUMN, [
45
46
  {
46
47
  attrName: AttrName.alias,
47
48
  endContextList: [SelectItemContext.name],
48
49
  },
49
50
  ], {
50
- declareType: ColumnDeclareType.EXPRESSION,
51
+ declareType: isSimpleColumn
52
+ ? ColumnDeclareType.LITERAL
53
+ : ColumnDeclareType.EXPRESSION,
51
54
  });
52
55
  }
53
56
  }
57
+ isSimpleColumnReference(ctx) {
58
+ const text = ctx.getText();
59
+ // Simple column reference: no parentheses, no operators, no spaces
60
+ return (!text.includes('(') &&
61
+ !text.includes(' ') &&
62
+ !text.includes('+') &&
63
+ !text.includes('-') &&
64
+ !text.includes('*') &&
65
+ !text.includes('/'));
66
+ }
54
67
  /** ===== Statement begin */
55
68
  enterSingleStatement(ctx) {
56
69
  this.pushStmt(ctx, StmtContextType.COMMON_STMT);
@@ -25,6 +25,7 @@ export class MySQL extends BasicSQL {
25
25
  MySqlParser.RULE_functionName,
26
26
  MySqlParser.RULE_functionNameCreate,
27
27
  MySqlParser.RULE_columnName,
28
+ MySqlParser.RULE_columnNamePath,
28
29
  MySqlParser.RULE_columnNameCreate,
29
30
  ...this.excludeKeywordRules,
30
31
  ]);
@@ -88,7 +89,8 @@ export class MySQL extends BasicSQL {
88
89
  syntaxContextType = EntityContextType.FUNCTION_CREATE;
89
90
  break;
90
91
  }
91
- case MySqlParser.RULE_columnName: {
92
+ case MySqlParser.RULE_columnName:
93
+ case MySqlParser.RULE_columnNamePath: {
92
94
  syntaxContextType = EntityContextType.COLUMN;
93
95
  break;
94
96
  }
@@ -1,4 +1,4 @@
1
- import { ColumnCreateTableContext, ColumnNameCreateContext, CopyCreateTableContext, CreateDatabaseContext, CreateFunctionContext, CreateFunctionLoadableContext, CreateViewContext, DatabaseNameContext, DatabaseNameCreateContext, FunctionNameCreateContext, InsertStatementContext, QueryCreateTableContext, SelectExpressionElementContext, SelectStatementContext, SingleStatementContext, TableNameContext, TableNameCreateContext, ViewNameContext, ViewNameCreateContext, TableAllColumnsContext, SelectLiteralColumnNameContext, AtomSubQueryTableSourceContext, SelectElementsContext, PureAllColumnsContext } 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, PureAllColumnsContext, SelectElement_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 {
@@ -18,6 +18,7 @@ export declare class MySqlEntityCollector extends EntityCollector implements MyS
18
18
  exitTableAllColumns(ctx: TableAllColumnsContext): void;
19
19
  exitPureAllColumns(ctx: PureAllColumnsContext): void;
20
20
  exitSelectLiteralColumnName(ctx: SelectLiteralColumnNameContext): void;
21
+ exitSelectElement_dot_empty(ctx: SelectElement_dot_emptyContext): void;
21
22
  exitSelectExpressionElement(ctx: SelectExpressionElementContext): void;
22
23
  /** ===== Statement begin */
23
24
  enterSingleStatement(ctx: SingleStatementContext): void;
@@ -1,4 +1,4 @@
1
- import { ColumnCreateTableContext, CreateDefinitionContext, CreateFunctionContext, SelectElementContext, TableSourceItemContext, AtomTableItemContext, SubqueryTableItemContext, } from '../../lib/mysql/MySqlParser';
1
+ import { ColumnCreateTableContext, CreateDefinitionContext, CreateFunctionContext, TableSourceItemContext, AtomTableItemContext, SubqueryTableItemContext, SelectElement_labelContext, SelectElement_exprContext, } from '../../lib/mysql/MySqlParser';
2
2
  import { AttrName, ColumnDeclareType, EntityCollector, StmtContextType, TableDeclareType, } from '../common/entityCollector';
3
3
  import { EntityContextType } from '../common/types';
4
4
  export class MySqlEntityCollector extends EntityCollector {
@@ -79,20 +79,30 @@ export class MySqlEntityCollector extends EntityCollector {
79
79
  });
80
80
  }
81
81
  exitSelectLiteralColumnName(ctx) {
82
+ // Handle empty column case (e.g., "select from")
83
+ // When emptyColumn matches, the context has no actual tokens
84
+ if (!ctx.start || !ctx.stop || ctx.start.start > ctx.stop.stop) {
85
+ return;
86
+ }
82
87
  this.pushEntity(ctx, EntityContextType.COLUMN, [
83
88
  {
84
89
  attrName: AttrName.alias,
85
- endContextList: [SelectElementContext.name],
90
+ endContextList: [SelectElement_labelContext.name],
86
91
  },
87
92
  ], {
88
93
  declareType: ColumnDeclareType.LITERAL,
89
94
  });
90
95
  }
96
+ exitSelectElement_dot_empty(ctx) {
97
+ this.pushEntity(ctx, EntityContextType.COLUMN, [], {
98
+ declareType: ColumnDeclareType.LITERAL,
99
+ });
100
+ }
91
101
  exitSelectExpressionElement(ctx) {
92
102
  this.pushEntity(ctx, EntityContextType.COLUMN, [
93
103
  {
94
104
  attrName: AttrName.alias,
95
- endContextList: [SelectElementContext.name],
105
+ endContextList: [SelectElement_exprContext.name],
96
106
  },
97
107
  ], {
98
108
  declareType: ColumnDeclareType.EXPRESSION,
@@ -14,6 +14,7 @@ export class MysqlErrorListener extends ParseErrorListener {
14
14
  [MySqlParser.RULE_functionName, 'function'],
15
15
  [MySqlParser.RULE_functionNameCreate, 'function'],
16
16
  [MySqlParser.RULE_columnName, 'column'],
17
+ [MySqlParser.RULE_columnNamePath, 'column'],
17
18
  [MySqlParser.RULE_columnNameCreate, 'column'],
18
19
  ]);
19
20
  }
@@ -48,6 +49,7 @@ export class MysqlErrorListener extends ParseErrorListener {
48
49
  case MySqlParser.RULE_tableName:
49
50
  case MySqlParser.RULE_functionName:
50
51
  case MySqlParser.RULE_viewName:
52
+ case MySqlParser.RULE_columnNamePath:
51
53
  case MySqlParser.RULE_columnName: {
52
54
  if (!result.includes(`{existing}${name}`)) {
53
55
  result.push(`{existing}${name}`);
@@ -1,4 +1,4 @@
1
- import { type AlterTableStmtContext, type ColumnCreateTableContext, type ColumnNameCreateContext, type CreateDatabaseContext, type CreateForeignTableContext, type CreateFunctionStmtContext, type CreateMaterializedViewContext, type CreatePartitionForeignTableContext, type CreateViewContext, type DatabaseNameContext, type DatabaseNameCreateContext, type FunctionNameCreateContext, type InsertStatementContext, type ProcedureNameContext, type ProcedureNameCreateContext, type QueryCreateTableContext, SelectExpressionColumnNameContext, SelectLiteralColumnNameContext, type SelectStatementContext, type SingleStmtContext, TableAllColumnsContext, type TableNameContext, type TableNameCreateContext, type ViewNameContext, type ViewNameCreateContext, TargetListContext, SelectNoParensContext, XmlTableContext, FuncTableContext, SelectWithParensContext } from '../../lib/postgresql/PostgreSqlParser';
1
+ import { type AlterTableStmtContext, type ColumnCreateTableContext, type ColumnNameCreateContext, type CreateDatabaseContext, type CreateForeignTableContext, type CreateFunctionStmtContext, type CreateMaterializedViewContext, type CreatePartitionForeignTableContext, type CreateViewContext, type DatabaseNameContext, type DatabaseNameCreateContext, FuncTableContext, type FunctionNameCreateContext, type InsertStatementContext, type ProcedureNameContext, type ProcedureNameCreateContext, type QueryCreateTableContext, SelectExpressionColumnNameContext, SelectLiteralColumnNameContext, SelectNoParensContext, type SelectStatementContext, SelectWithParensContext, type SingleStmtContext, TableAllColumnsContext, type TableNameContext, type TableNameCreateContext, Target_dot_emptyContext, Target_emptyContext, TargetListContext, type ViewNameContext, type ViewNameCreateContext, XmlTableContext } from '../../lib/postgresql/PostgreSqlParser';
2
2
  import type { PostgreSqlParserListener } from '../../lib/postgresql/PostgreSqlParserListener';
3
3
  import { EntityCollector } from '../common/entityCollector';
4
4
  export declare class PostgreSqlEntityCollector extends EntityCollector implements PostgreSqlParserListener {
@@ -16,6 +16,8 @@ export declare class PostgreSqlEntityCollector extends EntityCollector implement
16
16
  exitColumnNameCreate(ctx: ColumnNameCreateContext): void;
17
17
  exitTargetList(ctx: TargetListContext): void;
18
18
  exitTableAllColumns(ctx: TableAllColumnsContext): void;
19
+ exitTarget_empty(ctx: Target_emptyContext): void;
20
+ exitTarget_dot_empty(ctx: Target_dot_emptyContext): void;
19
21
  exitSelectExpressionColumnName(ctx: SelectExpressionColumnNameContext): void;
20
22
  exitSelectLiteralColumnName(ctx: SelectLiteralColumnNameContext): void;
21
23
  exitProcedureName(ctx: ProcedureNameContext): void;
@@ -81,6 +81,7 @@ export class PostgreSqlEntityCollector extends EntityCollector {
81
81
  ]);
82
82
  }
83
83
  exitTargetList(ctx) {
84
+ // Only create QUERY_RESULT for targetList that is direct child of simpleSelect
84
85
  if (!isChildContextOf(ctx, PostgreSqlParser.RULE_simpleSelect))
85
86
  return;
86
87
  this.pushEntity(ctx, EntityContextType.QUERY_RESULT);
@@ -92,6 +93,18 @@ export class PostgreSqlEntityCollector extends EntityCollector {
92
93
  declareType: ColumnDeclareType.ALL,
93
94
  });
94
95
  }
96
+ exitTarget_empty(ctx) {
97
+ // Don't create entity for empty column here
98
+ // The targetList will create QUERY_RESULT entity
99
+ // Empty targetEl means the QUERY_RESULT has no columns
100
+ }
101
+ exitTarget_dot_empty(ctx) {
102
+ // Create COLUMN entity for incomplete column reference (e.g., "tb.|")
103
+ // This allows completion to suggest columns from table "tb"
104
+ this.pushEntity(ctx, EntityContextType.COLUMN, [], {
105
+ declareType: ColumnDeclareType.LITERAL,
106
+ });
107
+ }
95
108
  exitSelectExpressionColumnName(ctx) {
96
109
  this.pushEntity(ctx, EntityContextType.COLUMN, [
97
110
  {
@@ -30,6 +30,7 @@ export class SparkSQL extends BasicSQL {
30
30
  SparkSqlParser.RULE_functionNameCreate,
31
31
  SparkSqlParser.RULE_columnName,
32
32
  SparkSqlParser.RULE_columnNamePath,
33
+ SparkSqlParser.RULE_columnNamePathAllowEmpty,
33
34
  SparkSqlParser.RULE_columnNameCreate,
34
35
  ...this.excludeKeywordRules,
35
36
  ]);
@@ -101,7 +102,8 @@ export class SparkSQL extends BasicSQL {
101
102
  syntaxContextType = EntityContextType.COLUMN_CREATE;
102
103
  break;
103
104
  }
104
- case SparkSqlParser.RULE_columnNamePath: {
105
+ case SparkSqlParser.RULE_columnNamePath:
106
+ case SparkSqlParser.RULE_columnNamePathAllowEmpty: {
105
107
  if (candidateRule.ruleList.includes(SparkSqlParser.RULE_whenClause) ||
106
108
  candidateRule.ruleList.includes(SparkSqlParser.RULE_whereClause) ||
107
109
  candidateRule.ruleList.includes(SparkSqlParser.RULE_joinRelation) ||
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-sql-parser",
3
- "version": "4.5.0-beta.2",
3
+ "version": "4.5.0",
4
4
  "authors": "DTStack Corporation",
5
5
  "description": "SQL Parsers for BigData, built with antlr4",
6
6
  "keywords": [