Skip to content

Commit

Permalink
feat(postgresql): add pg expression column
Browse files Browse the repository at this point in the history
  • Loading branch information
LuckyFBB committed Oct 17, 2024
1 parent 84c1008 commit 427acb1
Show file tree
Hide file tree
Showing 10 changed files with 10,219 additions and 9,888 deletions.
55 changes: 29 additions & 26 deletions src/grammar/postgresql/PostgreSqlParser.g4
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
/*
* [The "MIT license"]
* Copyright (C) 2014 Sam Harwell, Tunnel Vision Laboratories, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* [The "MIT license"] Copyright (C) 2014 Sam Harwell, Tunnel Vision Laboratories, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* 1. The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 2. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
* 3. Except as contained in this notice, the name of Tunnel Vision
* Laboratories, LLC. shall not be used in advertising or otherwise to
* promote the sale, use or other dealings in this Software without prior
* written authorization from Tunnel Vision Laboratories, LLC.
*
* 1. The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software. 2. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE. 3. Except as contained in this notice, the name of Tunnel Vision
* Laboratories, LLC. shall not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization from Tunnel Vision
* Laboratories, LLC.
*/

/**
* This file is an adaptation of antlr's sql/postgresql/PostgreSQLParser.g4 grammar.
* Reference: https://github.com/antlr/grammars-v4/blob/master/sql/postgresql/PostgreSQLParser.g4
* This file is an adaptation of antlr's sql/postgresql/PostgreSQLParser.g4 grammar. Reference:
* https://github.com/antlr/grammars-v4/blob/master/sql/postgresql/PostgreSQLParser.g4
*/

/**
Expand Down Expand Up @@ -2409,7 +2404,7 @@ primaryExpression
| explicit_row
| OPEN_PAREN expression COMMA expr_list CLOSE_PAREN
| row KW_OVERLAPS row
| qualified_name
| column_name_path
| primaryExpression TYPECAST typename
| (PLUS | MINUS) primaryExpression
| primaryExpression qual_op primaryExpression?
Expand Down Expand Up @@ -2504,6 +2499,10 @@ window_clause
: KW_WINDOW window_definition (COMMA window_definition)*
;

having_clause
: KW_HAVING expression
;

window_definition
: colid KW_AS window_specification
;
Expand Down Expand Up @@ -2743,6 +2742,10 @@ column_name
| {this.shouldMatchEmpty()}? # columnNameMatch
;

column_name_path
: colid opt_indirection
;

column_name_create
: colid # columnNameCreate
;
Expand Down Expand Up @@ -3631,5 +3634,5 @@ any_identifier
;

sql_expression
: target_list? into_clause? from_clause? where_clause? group_clause? (KW_HAVING expression)? window_clause?
: target_list? into_clause? from_clause? where_clause? group_clause? having_clause? window_clause?
;
4 changes: 3 additions & 1 deletion src/lib/postgresql/PostgreSqlParser.interp

Large diffs are not rendered by default.

19,837 changes: 9,978 additions & 9,859 deletions src/lib/postgresql/PostgreSqlParser.ts

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions src/lib/postgresql/PostgreSqlParserListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ import { Document_or_contentContext } from "./PostgreSqlParser.js";
import { Xmlexists_argumentContext } from "./PostgreSqlParser.js";
import { Xml_passing_mechContext } from "./PostgreSqlParser.js";
import { Window_clauseContext } from "./PostgreSqlParser.js";
import { Having_clauseContext } from "./PostgreSqlParser.js";
import { Window_definitionContext } from "./PostgreSqlParser.js";
import { Over_clauseContext } from "./PostgreSqlParser.js";
import { Window_specificationContext } from "./PostgreSqlParser.js";
Expand Down Expand Up @@ -425,6 +426,7 @@ import { ProcedureNameContext } from "./PostgreSqlParser.js";
import { ProcedureNameCreateContext } from "./PostgreSqlParser.js";
import { ColumnNameContext } from "./PostgreSqlParser.js";
import { ColumnNameMatchContext } from "./PostgreSqlParser.js";
import { Column_name_pathContext } from "./PostgreSqlParser.js";
import { ColumnNameCreateContext } from "./PostgreSqlParser.js";
import { FunctionNameCreateContext } from "./PostgreSqlParser.js";
import { FunctionNameContext } from "./PostgreSqlParser.js";
Expand Down Expand Up @@ -4209,6 +4211,16 @@ export class PostgreSqlParserListener implements ParseTreeListener {
* @param ctx the parse tree
*/
exitWindow_clause?: (ctx: Window_clauseContext) => void;
/**
* Enter a parse tree produced by `PostgreSqlParser.having_clause`.
* @param ctx the parse tree
*/
enterHaving_clause?: (ctx: Having_clauseContext) => void;
/**
* Exit a parse tree produced by `PostgreSqlParser.having_clause`.
* @param ctx the parse tree
*/
exitHaving_clause?: (ctx: Having_clauseContext) => void;
/**
* Enter a parse tree produced by `PostgreSqlParser.window_definition`.
* @param ctx the parse tree
Expand Down Expand Up @@ -4753,6 +4765,16 @@ export class PostgreSqlParserListener implements ParseTreeListener {
* @param ctx the parse tree
*/
exitColumnNameMatch?: (ctx: ColumnNameMatchContext) => void;
/**
* Enter a parse tree produced by `PostgreSqlParser.column_name_path`.
* @param ctx the parse tree
*/
enterColumn_name_path?: (ctx: Column_name_pathContext) => void;
/**
* Exit a parse tree produced by `PostgreSqlParser.column_name_path`.
* @param ctx the parse tree
*/
exitColumn_name_path?: (ctx: Column_name_pathContext) => void;
/**
* Enter a parse tree produced by the `columnNameCreate`
* labeled alternative in `PostgreSqlParser.column_name_create`.
Expand Down
14 changes: 14 additions & 0 deletions src/lib/postgresql/PostgreSqlParserVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ import { Document_or_contentContext } from "./PostgreSqlParser.js";
import { Xmlexists_argumentContext } from "./PostgreSqlParser.js";
import { Xml_passing_mechContext } from "./PostgreSqlParser.js";
import { Window_clauseContext } from "./PostgreSqlParser.js";
import { Having_clauseContext } from "./PostgreSqlParser.js";
import { Window_definitionContext } from "./PostgreSqlParser.js";
import { Over_clauseContext } from "./PostgreSqlParser.js";
import { Window_specificationContext } from "./PostgreSqlParser.js";
Expand Down Expand Up @@ -425,6 +426,7 @@ import { ProcedureNameContext } from "./PostgreSqlParser.js";
import { ProcedureNameCreateContext } from "./PostgreSqlParser.js";
import { ColumnNameContext } from "./PostgreSqlParser.js";
import { ColumnNameMatchContext } from "./PostgreSqlParser.js";
import { Column_name_pathContext } from "./PostgreSqlParser.js";
import { ColumnNameCreateContext } from "./PostgreSqlParser.js";
import { FunctionNameCreateContext } from "./PostgreSqlParser.js";
import { FunctionNameContext } from "./PostgreSqlParser.js";
Expand Down Expand Up @@ -2722,6 +2724,12 @@ export class PostgreSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Re
* @return the visitor result
*/
visitWindow_clause?: (ctx: Window_clauseContext) => Result;
/**
* Visit a parse tree produced by `PostgreSqlParser.having_clause`.
* @param ctx the parse tree
* @return the visitor result
*/
visitHaving_clause?: (ctx: Having_clauseContext) => Result;
/**
* Visit a parse tree produced by `PostgreSqlParser.window_definition`.
* @param ctx the parse tree
Expand Down Expand Up @@ -3045,6 +3053,12 @@ export class PostgreSqlParserVisitor<Result> extends AbstractParseTreeVisitor<Re
* @return the visitor result
*/
visitColumnNameMatch?: (ctx: ColumnNameMatchContext) => Result;
/**
* Visit a parse tree produced by `PostgreSqlParser.column_name_path`.
* @param ctx the parse tree
* @return the visitor result
*/
visitColumn_name_path?: (ctx: Column_name_pathContext) => Result;
/**
* Visit a parse tree produced by the `columnNameCreate`
* labeled alternative in `PostgreSqlParser.column_name_create`.
Expand Down
15 changes: 15 additions & 0 deletions src/parser/postgresql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class PostgreSQL extends BasicSQL<PostgreSqlLexer, ProgramContext, Postgr
PostgreSqlParser.RULE_procedure_name, // procedure name
PostgreSqlParser.RULE_column_name_create, // column name that will be created
PostgreSqlParser.RULE_column_name, // column name
PostgreSqlParser.RULE_column_name_path, // column name
]);

protected get splitListener() {
Expand Down Expand Up @@ -125,6 +126,20 @@ export class PostgreSQL extends BasicSQL<PostgreSqlLexer, ProgramContext, Postgr
syntaxContextType = EntityContextType.COLUMN;
break;
}
case PostgreSqlParser.RULE_column_name_path: {
if (
candidateRule.ruleList.includes(PostgreSqlParser.RULE_group_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_sort_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_limit_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_where_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_having_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_window_clause) ||
candidateRule.ruleList.includes(PostgreSqlParser.RULE_triggerwhen)
) {
syntaxContextType = EntityContextType.COLUMN;
}
break;
}
default:
break;
}
Expand Down
8 changes: 6 additions & 2 deletions src/parser/postgresql/postgreErrorListener.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class PostgreSqlErrorListener extends ParseErrorListener {
[PostgreSqlParser.RULE_function_name, 'function'],
[PostgreSqlParser.RULE_function_name_create, 'function'],
[PostgreSqlParser.RULE_column_name, 'column'],
[PostgreSqlParser.RULE_column_name_path, 'column'],
[PostgreSqlParser.RULE_column_name_create, 'column'],
[PostgreSqlParser.RULE_schema_name_create, 'schema'],
[PostgreSqlParser.RULE_schema_name, 'schema'],
Expand Down Expand Up @@ -54,8 +55,11 @@ export class PostgreSqlErrorListener extends ParseErrorListener {
case PostgreSqlParser.RULE_view_name:
case PostgreSqlParser.RULE_database_name:
case PostgreSqlParser.RULE_procedure_name:
case PostgreSqlParser.RULE_column_name: {
result.push(`{existing}${name}`);
case PostgreSqlParser.RULE_column_name:
case PostgreSqlParser.RULE_column_name_path: {
if (!result.includes(`{existing}${name}`)) {
result.push(`{existing}${name}`);
}
break;
}
case PostgreSqlParser.RULE_table_name_create:
Expand Down
9 changes: 9 additions & 0 deletions test/parser/postgresql/errorListener.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const sql1 = `ALTER EVENT`;
const sql2 = `CREATE FUNCTION `;
const sql3 = `SELECT name, altitude FROM ONLY cities WHERE `;
const sql4 = `DROP PROCEDURE name1 a`;
const sql5 = `SELECT * FROM db.tbs GROUP BY sum( `;

describe('PostgreSQL validate invalid sql and test msg', () => {
const pgSQL = new PostgreSQL();
Expand Down Expand Up @@ -45,6 +46,14 @@ describe('PostgreSQL validate invalid sql and test msg', () => {
);
});

test('validate unComplete sql5', () => {
const errors = pgSQL.validate(sql5);
expect(errors.length).toBe(1);
expect(errors[0].message).toBe(
`Statement is incomplete, expecting an existing column or an existing function or a keyword`
);
});

test('validate random text cn', () => {
pgSQL.locale = 'zh_CN';
const errors = pgSQL.validate(randomText);
Expand Down
10 changes: 10 additions & 0 deletions test/parser/postgresql/suggestion/fixtures/syntaxSuggestion.sql
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,13 @@ SELECT * FROM db.tbs GROUP BY (col1, col2) ORDER BY col3;
TRUNCATE TABLE ;

TRUNCATE TABLE t1;

SELECT * FROM db.tbs GROUP BY sum(length(col1+col2)) ORDER BY length(sum(col1/clo2));

VALUES (1, '3'), (3, 'sdsd') ORDER BY sort_expression ASC LIMIT id = 1;

CREATE OR REPLACE RULE name AS ON SELECT TO table_name WHERE length(y+x) = 3 DO INSTEAD NOTHING;

WITH query_name (id) AS (SELECT id FROM table_expression) SELECT DISTINCT ON (col1) random() AS name1 FROM table_expression WHERE name1=name1 GROUP BY id HAVING sum(len+y) < interval '5 hours' WINDOW w AS (PARTITION BY depname ORDER BY salary DESC) EXCEPT (SELECT * FROM others) ORDER BY salary USING > NULLS FIRST OFFSET start FETCH NEXT ROW ONLY FOR KEY SHARE OF table_name NOWAIT;

CREATE CONSTRAINT TRIGGER trig_name INSTEAD OF INSERT OR UPDATE ON table_name FROM referenced_table_name WHEN (OLD.balance IS DISTINCT FROM NEW.balance) EXECUTE PROCEDURE function_name ();
Loading

0 comments on commit 427acb1

Please sign in to comment.