diff --git a/src/site/sphinx/unsupported.rst b/src/site/sphinx/unsupported.rst index ae9ccdc214..f81ab87d3e 100644 --- a/src/site/sphinx/unsupported.rst +++ b/src/site/sphinx/unsupported.rst @@ -11,10 +11,10 @@ Missing syntax is added on demand — please `open an issue parser.withDialect(Dialect.POSTGRESQL)); + DoStatement block = (DoStatement) statements.get(0); + String body = block.getCode().getValue(); + // body: BEGIN RAISE NOTICE 'hello'; END + // statements.get(1) is the following SELECT. + +Semicolons and SQL statements inside the body remain part of its string literal; +they do not split the surrounding script into additional statements. + With ``Dialect.POSTGRESQL``, ``#`` terminates an unquoted identifier, so JSON operators such as ``js#>>'{a}'`` and ``js#>'{a}'`` work without surrounding spaces. Quote identifiers containing ``#``, for example ``"js#"``. Other diff --git a/src/test/java/net/sf/jsqlparser/statement/DoStatementTest.java b/src/test/java/net/sf/jsqlparser/statement/DoStatementTest.java index a38c0b6157..6c5b495ec4 100644 --- a/src/test/java/net/sf/jsqlparser/statement/DoStatementTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/DoStatementTest.java @@ -12,6 +12,8 @@ import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.junit.jupiter.api.Assertions.*; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import net.sf.jsqlparser.JSQLParserException; @@ -56,14 +58,35 @@ void roundTripsBodyAndLanguagePosition(String sql) throws Exception { @Test void preservesProceduralBodyAndFollowingStatementsIssue1946() throws Exception { - String body = "$$\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM comm.permission_operation) THEN\n" - + " INSERT INTO comm.permission_operation (permission_operation_id) VALUES (1) " - + "ON CONFLICT (permission_operation_id) DO NOTHING;\n END IF;\nEND $$"; - Statements statements = CCJSqlParserUtil.parseStatements("DO " + body + "; SELECT 1;", - p -> p.withDialect(Dialect.POSTGRESQL)); - assertEquals(2, statements.size()); - assertEquals(body, ((DoStatement) statements.get(0)).getCode().toString()); - assertEquals("SELECT 1", statements.get(1).toString()); + String sql; + try (InputStream input = getClass().getResourceAsStream("/postgresql/do-issue1946.sql")) { + assertNotNull(input); + sql = new String(input.readAllBytes(), StandardCharsets.UTF_8).strip(); + } + String body = sql.substring(sql.indexOf("$$"), sql.lastIndexOf("$$") + 2); + Statements statements = + CCJSqlParserUtil.parseStatements("SELECT 0;\n" + sql + "\nSELECT 1;", + p -> p.withDialect(Dialect.POSTGRESQL).withUnsupportedStatements(false)); + assertEquals(3, statements.size()); + assertEquals("SELECT 0", statements.get(0).toString()); + DoStatement block = assertInstanceOf(DoStatement.class, statements.get(1)); + assertEquals(body, block.getCode().toString()); + assertEquals(body.substring(2, body.length() - 2), block.getCode().getValue()); + assertEquals("SELECT 1", statements.get(2).toString()); + + StringBuilder output = new StringBuilder(); + for (Statement statement : statements) { + statement.accept(new StatementDeParser(output), null); + output.append(";\n"); + } + assertEquals("SELECT 0;\nDO " + body + ";\nSELECT 1;\n", output.toString()); + Statements reparsed = CCJSqlParserUtil.parseStatements(output.toString(), + p -> p.withDialect(Dialect.POSTGRESQL).withUnsupportedStatements(false)); + assertEquals(3, reparsed.size()); + assertEquals(body, + assertInstanceOf(DoStatement.class, reparsed.get(1)).getCode().toString()); + assertEquals("SELECT 0", reparsed.get(0).toString()); + assertEquals("SELECT 1", reparsed.get(2).toString()); } @Test diff --git a/src/test/resources/postgresql/do-issue1946.sql b/src/test/resources/postgresql/do-issue1946.sql new file mode 100644 index 0000000000..33b3092d58 --- /dev/null +++ b/src/test/resources/postgresql/do-issue1946.sql @@ -0,0 +1,41 @@ +--- +-- #%L +-- JSQLParser library +-- %% +-- Copyright (C) 2004 - 2026 JSQLParser +-- %% +-- Dual licensed under GNU LGPL 2.1 or Apache License 2.0 +-- #L% +--- +DO $$ +BEGIN + IF NOT EXISTS( select 1 from comm.permission_operation where permission_operation_code = 'ecg_report_time_modify') and EXISTS( select 1 from comm.permission where permission_code = 'data_modify') + THEN + INSERT INTO comm.permission_operation + (permission_operation_id, + permission_id, + permission_operation_code, + permission_operation_name, + "type", + "version", + his_org_id, + his_creater_id, + his_creater_name, + his_create_time, + his_updater_id, + his_update_time) + VALUES + ((select max(permission_operation_id) + 1 from comm.permission_operation), + (select permission_id from comm.permission where permission_code = 'data_modify' limit 1), + 'ecg_report_time_modify', + '心电报告时间修改', + '1', + 0, + (select his_org_id from comm.hospital limit 1), + 1, + '系统管理员', + now(), + 1, + now()) on conflict(permission_operation_id) do nothing; + END IF; +END $$;