From dcbec76a3afb940dfbd7eeb02a13e796d03bd835 Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Tue, 16 Jun 2026 17:29:59 -0500 Subject: [PATCH 1/7] Support replicating index creation (and use parsed queries for transformation) --- .github/workflows/test.yml | 2 +- Makefile | 10 +- README.md | 9 +- expected/05_allowed.out | 504 +- expected/06_multi_1.out | 44 +- expected/07_edges.out | 24 +- expected/13_transaction.out | 156 +- expected/15_new_set_behavior.out | 6 +- expected/16_multi_set_tags.out | 18 +- expected/19_include_only_repset_tables_3.out | 10 +- expected/20_include_only_repset_tables_4.out | 12 +- expected/22_is_deployed.out | 8 +- expected/23_1_4_features.out | 24 +- expected/24_sub_retries.out | 370 +- expected/25_1_5_features.out | 74 +- expected/33_allowed.out | 504 +- expected/34_multi_1.out | 44 +- expected/35_edges.out | 24 +- expected/41_transaction.out | 156 +- expected/43_new_set_behavior.out | 6 +- expected/44_multi_set_tags.out | 18 +- expected/47_include_only_repset_tables_3.out | 10 +- expected/48_include_only_repset_tables_4.out | 12 +- expected/50_is_deployed.out | 8 +- expected/51_1_4_features.out | 24 +- expected/52_sub_retries.out | 370 +- expected/53_1_5_features.out | 74 +- expected/56_1_6_features.out | 11 - expected/57_2_4_features.out | 61 + ...ve_features.out => 99_native_features.out} | 0 functions/rewrite_transaction_safe.sql | 6 + functions/set_tag_defaults.sql | 6 + pgl_ddl_deploy--2.3--2.4.sql | 752 + pgl_ddl_deploy--2.4.sql | 5918 ++++++++ pgl_ddl_deploy-sql-maker.sh | 7 +- pgl_ddl_deploy.c | 55 + pgl_ddl_deploy.control | 2 +- postgres_deparse.c | 12253 ++++++++++++++++ postgres_deparse.h | 66 + schema/2.4.sql | 1 + sql/56_1_6_features.sql | 12 - sql/57_2_4_features.sql | 43 + ...ve_features.sql => 99_native_features.sql} | 0 test_all_versions.sh | 2 +- views/event_trigger_schema.sql | 11 +- 45 files changed, 20434 insertions(+), 1293 deletions(-) create mode 100644 expected/57_2_4_features.out rename expected/{57_native_features.out => 99_native_features.out} (100%) create mode 100644 functions/rewrite_transaction_safe.sql create mode 100644 pgl_ddl_deploy--2.3--2.4.sql create mode 100644 pgl_ddl_deploy--2.4.sql create mode 100644 postgres_deparse.c create mode 100644 postgres_deparse.h create mode 100644 schema/2.4.sql create mode 100644 sql/57_2_4_features.sql rename sql/{57_native_features.sql => 99_native_features.sql} (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a206e53..08799ed 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: pg_version: ["11", "12", "13", "14", "15", "16", "17", "18"] - from_version: ["2.2", "2.3"] + from_version: ["2.3", "2.4"] steps: - uses: actions/checkout@v6 - name: Remove default PostgreSQL diff --git a/Makefile b/Makefile index d4bea6c..20b80c2 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,11 @@ DATA = pgl_ddl_deploy--1.0.sql pgl_ddl_deploy--1.0--1.1.sql \ pgl_ddl_deploy--2.0.sql pgl_ddl_deploy--2.0--2.1.sql \ pgl_ddl_deploy--2.1.sql pgl_ddl_deploy--2.1--2.2.sql \ pgl_ddl_deploy--2.2.sql pgl_ddl_deploy--2.2--2.3.sql \ - pgl_ddl_deploy--2.3.sql -MODULES = pgl_ddl_deploy ddl_deparse + pgl_ddl_deploy--2.3.sql pgl_ddl_deploy--2.3--2.4.sql \ + pgl_ddl_deploy--2.4.sql +MODULES = ddl_deparse +MODULE_big = pgl_ddl_deploy +OBJS = postgres_deparse.o pgl_ddl_deploy.o REGRESS := 01_create_ext 02_setup 03_add_configs 04_deploy 04_deploy_update \ 05_allowed 06_multi 07_edges 08_ignored \ @@ -52,7 +55,8 @@ REGRESS := 01_create_ext 02_setup 03_add_configs 04_deploy 04_deploy_update \ 54_new_setup \ 55_raise_message \ 56_1_6_features \ - 57_native_features + 57_2_4_features \ + 99_native_features PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) diff --git a/README.md b/README.md index 7d54d60..7cb05f8 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ https://innovation.enova.com/pursuing-postgres-ddl-replication/ # Release Notes -### Release 2.3 +### Release 2.4 Summary of changes: -* Support for Postgres 17 & 18 +* Support for replicating index DDL ### Release 2.2 Summary of changes: @@ -356,6 +356,11 @@ SQL statement with a single node `parsetree`) will be eligible for propagation. be maintained by DDL replication. Thus only `ALTER TABLE` statements are permitted here. This option is incompatible with `include_schema_regex`. +- `include_indexes`: if true, will replicate `CREATE INDEX`/`ALTER INDEX`/`DROP INDEX` + statements. This can be undesirable if the replica is intended to have different + configuration from the primary. Also, indexes cannot be created with `CREATE INDEX CONCURRENTLY` + and will therefore potentially block operations on the table, which can be problematic + if the replica is in active read usage. - `queue_subscriber_failures`: if true, DDL will be allowed to fail on subscriber without breaking replication, and queued for retry using function `pgl_ddl_deploy.retry_all_subscriber_logs()`. This is useful for example if you diff --git a/expected/05_allowed.out b/expected/05_allowed.out index 2d9f4ea..415ee16 100644 --- a/expected/05_allowed.out +++ b/expected/05_allowed.out @@ -14,73 +14,73 @@ SELECT * FROM check_rep_tables(); (4 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (4 rows) ALTER TABLE foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (8 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); DROP TABLE foo CASCADE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (10 rows) CREATE FUNCTION foo() RETURNS INT AS @@ -89,64 +89,64 @@ SELECT 1; $BODY$ LANGUAGE SQL STABLE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+--------------------------------------+-------------------------------------- - test4 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+--------------------------------------+----------------------------------------- + test4 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; (10 rows) ALTER FUNCTION foo() OWNER TO current_user; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+---------------------------------------------+--------------------------------------------- - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; (10 rows) @@ -159,20 +159,20 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test2 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test1 | DROP FUNCTION foo(); | DROP FUNCTION foo(); - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | (10 rows) CREATE VIEW fooview AS @@ -180,46 +180,46 @@ SELECT 1 AS myfield; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+---------------------------------------------+--------------------------------------------- - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test4 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test2 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test1 | DROP FUNCTION foo(); | DROP FUNCTION foo(); - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; (10 rows) ALTER VIEW fooview RENAME TO barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------+--------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------+--------------------------------------------- test4 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test3 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test2 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test1 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test4 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); (10 rows) DROP VIEW barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------+--------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------+--------------------------------------------- test4 | DROP VIEW barview; | DROP VIEW barview; test3 | DROP VIEW barview; | DROP VIEW barview; test2 | DROP VIEW barview; | DROP VIEW barview; @@ -228,10 +228,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test2 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test1 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | (10 rows) CREATE SEQUENCE foo; @@ -313,34 +313,34 @@ SELECT * FROM check_rep_tables(); (8 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; (10 rows) ALTER TABLE foobar.foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); (10 rows) INSERT INTO foobar.foo (bla) VALUES (1),(2),(3); @@ -356,8 +356,8 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test2 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; (10 rows) CREATE FUNCTION foobar.foo() RETURNS INT AS @@ -366,48 +366,48 @@ SELECT 1; $BODY$ LANGUAGE SQL STABLE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------+--------------------------------------------- - test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test6 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test5 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test4 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------+------------------------------------------------ + test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test6 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test5 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test4 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; (10 rows) @@ -416,24 +416,24 @@ ALTER FUNCTION foobar.foo() OWNER TO current_user; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+----------------------------------------------------+---------------------------------------------------- - test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test6 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test5 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test4 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test3 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test2 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test1 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test6 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test5 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test4 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | (10 rows) DROP FUNCTION foobar.foo(); @@ -448,39 +448,39 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test2 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test1 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); - test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; + test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; (10 rows) CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------+------------------------------- - test8 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test7 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test6 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test5 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test4 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------+---------------------------------------------------- + test8 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test7 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test6 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test5 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test4 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test8 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test7 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); (10 rows) ALTER VIEW foobar.fooview RENAME TO barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+---------------------------------------------------- test8 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test7 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test6 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; @@ -489,10 +489,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test2 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test1 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; - test8 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test7 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test8 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test7 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | (10 rows) DROP VIEW foobar.barview; diff --git a/expected/06_multi_1.out b/expected/06_multi_1.out index 7f4c9f5..a37f8ac 100644 --- a/expected/06_multi_1.out +++ b/expected/06_multi_1.out @@ -70,12 +70,12 @@ COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; @@ -116,14 +116,14 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------- - test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; - test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-----------------------------------------------------------------------------+------------------------------------------------------------------------------ + test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; + test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test6 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; @@ -157,18 +157,18 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+----------------------------------------------- test4 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test3 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test2 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test1 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; - test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); + test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; diff --git a/expected/07_edges.out b/expected/07_edges.out index 14a7b1f..f33dc69 100644 --- a/expected/07_edges.out +++ b/expected/07_edges.out @@ -5,18 +5,18 @@ CREATE TABLE foo (id SERIAL PRIMARY KEY); --This is an edge case that currently can't be dealt with well with filtered replication. ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------------------------------+------------------------------------------------------------------ - test8 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test7 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test6 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test5 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test4 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test3 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test2 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test1 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test4 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id SERIAL PRIMARY KEY); - test3 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id SERIAL PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------------------------------+------------------------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test7 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test6 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test5 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test4 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test3 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test2 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test1 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test4 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id serial PRIMARY KEY); (10 rows) DROP TABLE foobar.foo CASCADE; diff --git a/expected/13_transaction.out b/expected/13_transaction.out index c66b9ec..d1f4d78 100644 --- a/expected/13_transaction.out +++ b/expected/13_transaction.out @@ -15,24 +15,24 @@ SELECT * FROM check_rep_tables(); (4 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | test8 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test7 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test6 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; @@ -43,28 +43,28 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i ALTER TABLE foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | test8 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test7 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; (10 rows) @@ -72,24 +72,24 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i INSERT INTO foo (bla) VALUES (1),(2),(3); DROP TABLE foo CASCADE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (10 rows) CREATE TABLE foobar.foo(id serial primary key); @@ -107,34 +107,34 @@ SELECT * FROM check_rep_tables(); (8 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; (10 rows) ALTER TABLE foobar.foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); (10 rows) INSERT INTO foobar.foo (bla) VALUES (1),(2),(3); @@ -150,8 +150,8 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test2 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; (10 rows) COMMIT; diff --git a/expected/15_new_set_behavior.out b/expected/15_new_set_behavior.out index 2322c13..0bef49a 100644 --- a/expected/15_new_set_behavior.out +++ b/expected/15_new_set_behavior.out @@ -62,9 +62,9 @@ BEGIN; INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_only_repset_tables) VALUES ('temp_1', TRUE); SELECT create_tags, drop_tags FROM pgl_ddl_deploy.set_configs WHERE set_name = 'temp_1'; - create_tags | drop_tags ------------------+----------- - {"ALTER TABLE"} | + create_tags | drop_tags +-------------------------+----------- + {"ALTER TABLE",COMMENT} | (1 row) ROLLBACK; diff --git a/expected/16_multi_set_tags.out b/expected/16_multi_set_tags.out index 4f3d990..5065919 100644 --- a/expected/16_multi_set_tags.out +++ b/expected/16_multi_set_tags.out @@ -11,11 +11,11 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - create_tags | set_name | ddl_sql_raw | ddl_sql_sent ---------------------------------------------------------------------------------------------------------------+----------+----------------------------------------------+---------------------------------------------- - {"CREATE VIEW","ALTER VIEW","CREATE FUNCTION","ALTER FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS + - | | SELECT * FROM viewer.foo; | SELECT * FROM viewer.foo; - {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo(id int primary key); + create_tags | set_name | ddl_sql_raw | ddl_sql_sent +--------------------------------------------------------------------------------------------------------------+----------+----------------------------------------------+-------------------------------------------------------- + {"CREATE VIEW","ALTER VIEW","CREATE FUNCTION","ALTER FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | + {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo (id int PRIMARY KEY); {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE SCHEMA viewer; | CREATE SCHEMA viewer; {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; (4 rows) @@ -28,13 +28,13 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - drop_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------------------------------------------------+----------+--------------------------------+-------------------------------- + drop_tags | set_name | ddl_sql_raw | ddl_sql_sent +----------------------------------------------------------+----------+--------------------------------+-------------------------------------------------------- {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP SCHEMA viewer; | DROP SCHEMA viewer; {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; - {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS + - | | SELECT * FROM viewer.foo; | SELECT * FROM viewer.foo; + {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | (4 rows) SELECT * FROM pgl_ddl_deploy.exceptions; diff --git a/expected/19_include_only_repset_tables_3.out b/expected/19_include_only_repset_tables_3.out index e49e53c..0a53398 100644 --- a/expected/19_include_only_repset_tables_3.out +++ b/expected/19_include_only_repset_tables_3.out @@ -9,8 +9,8 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; create_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------+---------------------+--------------------------------------------------+-------------------------------------------------- - {"ALTER TABLE"} | my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - {"ALTER TABLE"} | my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + {"ALTER TABLE"} | my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + {"ALTER TABLE"} | my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (2 rows) --Test renaming which was missing in 1.2 @@ -34,8 +34,8 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 20; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; - my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; + my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (9 rows) diff --git a/expected/20_include_only_repset_tables_4.out b/expected/20_include_only_repset_tables_4.out index a68836e..c54ca57 100644 --- a/expected/20_include_only_repset_tables_4.out +++ b/expected/20_include_only_repset_tables_4.out @@ -20,9 +20,9 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; - my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; + my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (10 rows) -- Test new subcommand functionality @@ -56,8 +56,8 @@ INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ---------------------+--------------------------------------------------------------------------------+-------------------------------------------------------------------------------- - my_special_tables_1 | ALTER TABLE special.fooz ADD COLUMN bar_id INT; | ALTER TABLE special.fooz ADD COLUMN bar_id INT; - my_special_tables_2 | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); + my_special_tables_1 | ALTER TABLE special.fooz ADD COLUMN bar_id INT; | ALTER TABLE special.fooz ADD COLUMN bar_id int; + my_special_tables_2 | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); | ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2); my_special_tables_1 | ALTER TABLE special.fooz DISABLE TRIGGER noop; | ALTER TABLE special.fooz DISABLE TRIGGER noop; my_special_tables_2 | ALTER TABLE special.bar RENAME TO barz; | ALTER TABLE special.bar RENAME TO barz; my_special_tables_1 | ALTER TABLE special.foo RENAME TO fooz; | ALTER TABLE special.foo RENAME TO fooz; @@ -65,7 +65,7 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; (10 rows) SET client_min_messages = warning; diff --git a/expected/22_is_deployed.out b/expected/22_is_deployed.out index 7a6f736..7a54a1b 100644 --- a/expected/22_is_deployed.out +++ b/expected/22_is_deployed.out @@ -108,10 +108,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; test2 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; test1 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; - test4 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); + test4 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test4 | DROP SCHEMA special; | DROP SCHEMA special; test3 | DROP SCHEMA special; | DROP SCHEMA special; (10 rows) diff --git a/expected/23_1_4_features.out b/expected/23_1_4_features.out index 1352e6b..a484b74 100644 --- a/expected/23_1_4_features.out +++ b/expected/23_1_4_features.out @@ -63,17 +63,17 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.ddl_only_replication FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | ddl_only_replication ----------------+------------------------------------------------+------------------------------------------------+---------------------- - test_ddl_only | DROP TABLE duper.man; | DROP TABLE duper.man; | t - test_ddl_only | DROP TABLE super.man CASCADE; | DROP TABLE super.man CASCADE; | f - test_ddl_only | ALTER TABLE duper.man ADD COLUMN foo text; | ALTER TABLE duper.man ADD COLUMN foo text; | t - test_ddl_only | ALTER TABLE super.man ADD COLUMN foo text; | ALTER TABLE super.man ADD COLUMN foo text; | f - test_ddl_only | CREATE TABLE duper.man(id serial primary key); | CREATE TABLE duper.man(id serial primary key); | t - test_ddl_only | CREATE SCHEMA duper; | CREATE SCHEMA duper; | t - test_ddl_only | CREATE TABLE super.man(id serial primary key); | CREATE TABLE super.man(id serial primary key); | f - test_ddl_only | CREATE SCHEMA super; | CREATE SCHEMA super; | f - test4 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f - test3 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f + set_name | ddl_sql_raw | ddl_sql_sent | ddl_only_replication +---------------+------------------------------------------------+-------------------------------------------------+---------------------- + test_ddl_only | DROP TABLE duper.man; | DROP TABLE duper.man; | t + test_ddl_only | DROP TABLE super.man CASCADE; | DROP TABLE super.man CASCADE; | f + test_ddl_only | ALTER TABLE duper.man ADD COLUMN foo text; | ALTER TABLE duper.man ADD COLUMN foo text; | t + test_ddl_only | ALTER TABLE super.man ADD COLUMN foo text; | ALTER TABLE super.man ADD COLUMN foo text; | f + test_ddl_only | CREATE TABLE duper.man(id serial primary key); | CREATE TABLE duper.man (id serial PRIMARY KEY); | t + test_ddl_only | CREATE SCHEMA duper; | CREATE SCHEMA duper; | t + test_ddl_only | CREATE TABLE super.man(id serial primary key); | CREATE TABLE super.man (id serial PRIMARY KEY); | f + test_ddl_only | CREATE SCHEMA super; | CREATE SCHEMA super; | f + test4 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f + test3 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f (10 rows) diff --git a/expected/24_sub_retries.out b/expected/24_sub_retries.out index ddeb8d8..68ecb84 100644 --- a/expected/24_sub_retries.out +++ b/expected/24_sub_retries.out @@ -2,36 +2,36 @@ --If adding new tests, it is best to keep this file as the last test before cleanup. SET client_min_messages = warning; SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(message::text, 'p_pid := (\d+)', 'p_pid := ?'), 'p_provider_name := (NULL|''\w+'')', 'p_provider_name := ?'), 'p_driver := (''\w+'')', 'p_driver := ?') as message FROM all_queues() WHERE NOT message::text LIKE '%notify_subscription_refresh%' ORDER BY queued_at; - pubnames | message_type | message ------------------------+--------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + pubnames | message_type | message +-----------------------+--------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER VIEW fooview RENAME TO barview;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -60,22 +60,22 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -84,22 +84,22 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -108,14 +108,14 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW foobar.fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW foobar.fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER VIEW foobar.fooview RENAME TO barview;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -172,12 +172,12 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foobar.foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foobar.foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -190,48 +190,48 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo, foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo, foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo, foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo, foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -256,34 +256,34 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -296,14 +296,14 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP VIEW viewer.vw_foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP VIEW viewer.vw_foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP VIEW viewer.vw_foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -320,38 +320,38 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial primary key, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial primary key, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial primary key, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial primary key, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial primary key, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial primary key, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy to happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy to happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy TO happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy TO happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -377,10 +377,10 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar RENAME TO barz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar RENAME TO barz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar RENAME TO barz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -390,16 +390,16 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ENABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ENABLE TRIGGER noop;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ENABLE TRIGGER noop;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id INT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id INT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id int;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id int;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -416,10 +416,10 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -429,9 +429,9 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA bla;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA bla;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA bla;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA bla;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA super;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA super;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE super.man(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE super.man(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE super.man (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE super.man (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA duper;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA duper;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE duper.man(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE duper.man(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE duper.man (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE duper.man (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE super.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE super.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE duper.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE duper.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE super.man CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE super.man CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " diff --git a/expected/25_1_5_features.out b/expected/25_1_5_features.out index 22120c2..d25cf5f 100644 --- a/expected/25_1_5_features.out +++ b/expected/25_1_5_features.out @@ -17,9 +17,9 @@ SET search_path TO public; SET ROLE test_pgl_ddl_deploy; CREATE TABLE foo(id serial primary key, bla int); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------------+--------------------------------------------------- - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------------+---------------------------------------------------- + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); (1 row) GRANT SELECT ON foo TO PUBLIC; @@ -27,10 +27,10 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (2 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); @@ -40,12 +40,12 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (4 rows) SELECT * FROM pgl_ddl_deploy.unhandled; @@ -73,13 +73,13 @@ SELECT pgl_ddl_deploy.deploy(id) FROM pgl_ddl_deploy.set_configs WHERE set_name SET ROLE test_pgl_ddl_deploy; CREATE TABLE foo(id serial primary key, bla int); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------------+--------------------------------------------------- - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------------+---------------------------------------------------- + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); (5 rows) GRANT SELECT ON foo TO PUBLIC; @@ -87,14 +87,14 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (6 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); @@ -104,16 +104,16 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (8 rows) SELECT * FROM pgl_ddl_deploy.unhandled; diff --git a/expected/33_allowed.out b/expected/33_allowed.out index 2d9f4ea..415ee16 100644 --- a/expected/33_allowed.out +++ b/expected/33_allowed.out @@ -14,73 +14,73 @@ SELECT * FROM check_rep_tables(); (4 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (4 rows) ALTER TABLE foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (8 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); DROP TABLE foo CASCADE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (10 rows) CREATE FUNCTION foo() RETURNS INT AS @@ -89,64 +89,64 @@ SELECT 1; $BODY$ LANGUAGE SQL STABLE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+--------------------------------------+-------------------------------------- - test4 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+--------------------------------------+----------------------------------------- + test4 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foo() RETURNS INT AS+| CREATE FUNCTION foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; (10 rows) ALTER FUNCTION foo() OWNER TO current_user; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+---------------------------------------------+--------------------------------------------- - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; (10 rows) @@ -159,20 +159,20 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test2 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test1 | DROP FUNCTION foo(); | DROP FUNCTION foo(); - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test4 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foo() RETURNS INT AS +| CREATE FUNCTION foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | (10 rows) CREATE VIEW fooview AS @@ -180,46 +180,46 @@ SELECT 1 AS myfield; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+---------------------------------------------+--------------------------------------------- - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test4 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test2 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test1 | DROP FUNCTION foo(); | DROP FUNCTION foo(); - test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; - test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO current_user; + test4 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foo() OWNER TO current_user; | ALTER FUNCTION foo() OWNER TO CURRENT_USER; (10 rows) ALTER VIEW fooview RENAME TO barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------+--------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------+--------------------------------------------- test4 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test3 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test2 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test1 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test4 | DROP FUNCTION foo(); | DROP FUNCTION foo(); test3 | DROP FUNCTION foo(); | DROP FUNCTION foo(); (10 rows) DROP VIEW barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------+--------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------+--------------------------------------------- test4 | DROP VIEW barview; | DROP VIEW barview; test3 | DROP VIEW barview; | DROP VIEW barview; test2 | DROP VIEW barview; | DROP VIEW barview; @@ -228,10 +228,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test2 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; test1 | ALTER VIEW fooview RENAME TO barview; | ALTER VIEW fooview RENAME TO barview; - test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test4 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW fooview AS +| CREATE VIEW fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | (10 rows) CREATE SEQUENCE foo; @@ -313,34 +313,34 @@ SELECT * FROM check_rep_tables(); (8 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; (10 rows) ALTER TABLE foobar.foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); (10 rows) INSERT INTO foobar.foo (bla) VALUES (1),(2),(3); @@ -356,8 +356,8 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test2 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; (10 rows) CREATE FUNCTION foobar.foo() RETURNS INT AS @@ -366,48 +366,48 @@ SELECT 1; $BODY$ LANGUAGE SQL STABLE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------+--------------------------------------------- - test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test6 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test5 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test4 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test3 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test2 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test1 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS INT AS+ - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------+------------------------------------------------ + test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test6 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test5 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test4 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test3 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test2 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test1 | CREATE FUNCTION foobar.foo() RETURNS INT AS+| CREATE FUNCTION foobar.foo() RETURNS int AS $$+ + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; (10 rows) @@ -416,24 +416,24 @@ ALTER FUNCTION foobar.foo() OWNER TO current_user; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+----------------------------------------------------+---------------------------------------------------- - test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test6 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test5 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test4 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test3 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test2 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test1 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; - test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS INT AS + - | $BODY$ +| $BODY$ + - | SELECT 1; +| SELECT 1; + - | $BODY$ +| $BODY$ + - | LANGUAGE SQL STABLE; | LANGUAGE SQL STABLE; + test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test6 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test5 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test4 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test3 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test2 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test1 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test8 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | + test7 | CREATE FUNCTION foobar.foo() RETURNS INT AS +| CREATE FUNCTION foobar.foo() RETURNS int AS $$ + + | $BODY$ +| SELECT 1; + + | SELECT 1; +| $$ LANGUAGE sql STABLE; + | $BODY$ +| + | LANGUAGE SQL STABLE; | (10 rows) DROP FUNCTION foobar.foo(); @@ -448,39 +448,39 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test2 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test1 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); - test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; - test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO current_user; + test8 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; + test7 | ALTER FUNCTION foobar.foo() OWNER TO current_user; | ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER; (10 rows) CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------+------------------------------- - test8 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test7 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test6 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test5 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test4 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test3 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test2 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test1 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS+ - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------+---------------------------------------------------- + test8 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test7 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test6 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test5 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test4 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test3 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test2 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test1 | CREATE VIEW foobar.fooview AS+| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | test8 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); test7 | DROP FUNCTION foobar.foo(); | DROP FUNCTION foobar.foo(); (10 rows) ALTER VIEW foobar.fooview RENAME TO barview; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+---------------------------------------------------- test8 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test7 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test6 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; @@ -489,10 +489,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test2 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; test1 | ALTER VIEW foobar.fooview RENAME TO barview; | ALTER VIEW foobar.fooview RENAME TO barview; - test8 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; - test7 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS + - | SELECT 1 AS myfield; | SELECT 1 AS myfield; + test8 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | + test7 | CREATE VIEW foobar.fooview AS +| CREATE VIEW foobar.fooview AS SELECT 1 AS myfield; + | SELECT 1 AS myfield; | (10 rows) DROP VIEW foobar.barview; diff --git a/expected/34_multi_1.out b/expected/34_multi_1.out index 7f4c9f5..a37f8ac 100644 --- a/expected/34_multi_1.out +++ b/expected/34_multi_1.out @@ -70,12 +70,12 @@ COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; @@ -116,14 +116,14 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------- - test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; - test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-----------------------------------------------------------------------------+------------------------------------------------------------------------------ + test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; + test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test6 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; @@ -157,18 +157,18 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+----------------------------------------------- test4 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test3 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test2 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test1 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; - test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); + test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; diff --git a/expected/35_edges.out b/expected/35_edges.out index 14a7b1f..f33dc69 100644 --- a/expected/35_edges.out +++ b/expected/35_edges.out @@ -5,18 +5,18 @@ CREATE TABLE foo (id SERIAL PRIMARY KEY); --This is an edge case that currently can't be dealt with well with filtered replication. ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------------------------------+------------------------------------------------------------------ - test8 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test7 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test6 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test5 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test4 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test3 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test2 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test1 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); - test4 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id SERIAL PRIMARY KEY); - test3 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id SERIAL PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------------------------------+------------------------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test7 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test6 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test5 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test4 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test3 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test2 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test1 | ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id); | ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id); + test4 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foo (id SERIAL PRIMARY KEY); | CREATE TABLE foo (id serial PRIMARY KEY); (10 rows) DROP TABLE foobar.foo CASCADE; diff --git a/expected/41_transaction.out b/expected/41_transaction.out index c66b9ec..d1f4d78 100644 --- a/expected/41_transaction.out +++ b/expected/41_transaction.out @@ -15,24 +15,24 @@ SELECT * FROM check_rep_tables(); (4 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | test8 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test7 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test6 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; @@ -43,28 +43,28 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i ALTER TABLE foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test2 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test1 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test2 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test1 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | test8 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; test7 | DROP TABLE foobar.foo; | DROP TABLE foobar.foo; (10 rows) @@ -72,24 +72,24 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i INSERT INTO foo (bla) VALUES (1),(2),(3); DROP TABLE foo CASCADE; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+------------------------------------------+------------------------------------------ + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------------+------------------------------------------- test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test2 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla TEXT; - test4 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); - test3 | /*** +| /*** + - | In default schema +| In default schema + - | **/ +| **/ + - | CREATE TABLE foo(id serial primary key); | CREATE TABLE foo(id serial primary key); + test4 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test3 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test2 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test1 | ALTER TABLE foo ADD COLUMN bla TEXT; | ALTER TABLE foo ADD COLUMN bla text; + test4 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | + test3 | /*** +| CREATE TABLE foo (id serial PRIMARY KEY); + | In default schema +| + | **/ +| + | CREATE TABLE foo(id serial primary key); | (10 rows) CREATE TABLE foobar.foo(id serial primary key); @@ -107,34 +107,34 @@ SELECT * FROM check_rep_tables(); (8 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); test4 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; test3 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; (10 rows) ALTER TABLE foobar.foo ADD COLUMN bla TEXT; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------+------------------------------------------------- - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); - test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo(id serial primary key); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------+-------------------------------------------------- + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test6 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test5 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test4 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test3 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test2 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test1 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test8 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id serial primary key); | CREATE TABLE foobar.foo (id serial PRIMARY KEY); (10 rows) INSERT INTO foobar.foo (bla) VALUES (1),(2),(3); @@ -150,8 +150,8 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test2 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; - test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; - test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; + test8 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; + test7 | ALTER TABLE foobar.foo ADD COLUMN bla TEXT; | ALTER TABLE foobar.foo ADD COLUMN bla text; (10 rows) COMMIT; diff --git a/expected/43_new_set_behavior.out b/expected/43_new_set_behavior.out index cb8466a..e2e90cf 100644 --- a/expected/43_new_set_behavior.out +++ b/expected/43_new_set_behavior.out @@ -75,9 +75,9 @@ BEGIN; INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_only_repset_tables) VALUES ('temp_1', TRUE); SELECT create_tags, drop_tags FROM pgl_ddl_deploy.set_configs WHERE set_name = 'temp_1'; - create_tags | drop_tags ------------------+----------- - {"ALTER TABLE"} | + create_tags | drop_tags +-------------------------+----------- + {"ALTER TABLE",COMMENT} | (1 row) ROLLBACK; diff --git a/expected/44_multi_set_tags.out b/expected/44_multi_set_tags.out index 044236e..a83d83d 100644 --- a/expected/44_multi_set_tags.out +++ b/expected/44_multi_set_tags.out @@ -11,11 +11,11 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - create_tags | set_name | ddl_sql_raw | ddl_sql_sent ---------------------------------------------------------------------------------------------------------------+----------+----------------------------------------------+---------------------------------------------- - {"CREATE VIEW","ALTER VIEW","CREATE FUNCTION","ALTER FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS + - | | SELECT * FROM viewer.foo; | SELECT * FROM viewer.foo; - {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo(id int primary key); + create_tags | set_name | ddl_sql_raw | ddl_sql_sent +--------------------------------------------------------------------------------------------------------------+----------+----------------------------------------------+-------------------------------------------------------- + {"CREATE VIEW","ALTER VIEW","CREATE FUNCTION","ALTER FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | + {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo (id int PRIMARY KEY); {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | CREATE SCHEMA viewer; | CREATE SCHEMA viewer; {"ALTER TABLE","CREATE SEQUENCE","ALTER SEQUENCE","CREATE SCHEMA","CREATE TABLE","CREATE TYPE","ALTER TYPE"} | test1 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; (4 rows) @@ -28,13 +28,13 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - drop_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------------------------------------------------+----------+--------------------------------+-------------------------------- + drop_tags | set_name | ddl_sql_raw | ddl_sql_sent +----------------------------------------------------------+----------+--------------------------------+-------------------------------------------------------- {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP SCHEMA viewer; | DROP SCHEMA viewer; {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; - {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS + - | | SELECT * FROM viewer.foo; | SELECT * FROM viewer.foo; + {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | (4 rows) SELECT * FROM pgl_ddl_deploy.exceptions; diff --git a/expected/47_include_only_repset_tables_3.out b/expected/47_include_only_repset_tables_3.out index e49e53c..0a53398 100644 --- a/expected/47_include_only_repset_tables_3.out +++ b/expected/47_include_only_repset_tables_3.out @@ -9,8 +9,8 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; create_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------+---------------------+--------------------------------------------------+-------------------------------------------------- - {"ALTER TABLE"} | my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - {"ALTER TABLE"} | my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + {"ALTER TABLE"} | my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + {"ALTER TABLE"} | my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (2 rows) --Test renaming which was missing in 1.2 @@ -34,8 +34,8 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 20; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; - my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; + my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (9 rows) diff --git a/expected/48_include_only_repset_tables_4.out b/expected/48_include_only_repset_tables_4.out index a68836e..c54ca57 100644 --- a/expected/48_include_only_repset_tables_4.out +++ b/expected/48_include_only_repset_tables_4.out @@ -20,9 +20,9 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; - my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier TEXT; - my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy TEXT; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; + my_special_tables_2 | ALTER TABLE special.bar ADD COLUMN happier TEXT; | ALTER TABLE special.bar ADD COLUMN happier text; + my_special_tables_1 | ALTER TABLE special.foo ADD COLUMN happy TEXT; | ALTER TABLE special.foo ADD COLUMN happy text; (10 rows) -- Test new subcommand functionality @@ -56,8 +56,8 @@ INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ---------------------+--------------------------------------------------------------------------------+-------------------------------------------------------------------------------- - my_special_tables_1 | ALTER TABLE special.fooz ADD COLUMN bar_id INT; | ALTER TABLE special.fooz ADD COLUMN bar_id INT; - my_special_tables_2 | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); + my_special_tables_1 | ALTER TABLE special.fooz ADD COLUMN bar_id INT; | ALTER TABLE special.fooz ADD COLUMN bar_id int; + my_special_tables_2 | ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); | ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2); my_special_tables_1 | ALTER TABLE special.fooz DISABLE TRIGGER noop; | ALTER TABLE special.fooz DISABLE TRIGGER noop; my_special_tables_2 | ALTER TABLE special.bar RENAME TO barz; | ALTER TABLE special.bar RENAME TO barz; my_special_tables_1 | ALTER TABLE special.foo RENAME TO fooz; | ALTER TABLE special.foo RENAME TO fooz; @@ -65,7 +65,7 @@ WHERE c.set_name LIKE 'my_special_tables%' ORDER BY e.id DESC LIMIT 10; my_special_tables_2 | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; | ALTER TABLE special.bar RENAME COLUMN happier TO happierz; my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN id TO id_2; | ALTER TABLE special.foo RENAME COLUMN id TO id_2; my_special_tables_1 | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); | ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true); - my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy to happyz; + my_special_tables_1 | ALTER TABLE special.foo RENAME COLUMN happy to happyz; | ALTER TABLE special.foo RENAME COLUMN happy TO happyz; (10 rows) SET client_min_messages = warning; diff --git a/expected/50_is_deployed.out b/expected/50_is_deployed.out index 7a6f736..7a54a1b 100644 --- a/expected/50_is_deployed.out +++ b/expected/50_is_deployed.out @@ -108,10 +108,10 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; test2 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; test1 | DROP TABLE foobar CASCADE; | DROP TABLE foobar CASCADE; - test4 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); - test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial primary key); + test4 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); + test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test4 | DROP SCHEMA special; | DROP SCHEMA special; test3 | DROP SCHEMA special; | DROP SCHEMA special; (10 rows) diff --git a/expected/51_1_4_features.out b/expected/51_1_4_features.out index 837c2ef..e58aaf6 100644 --- a/expected/51_1_4_features.out +++ b/expected/51_1_4_features.out @@ -75,17 +75,17 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.ddl_only_replication FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | ddl_only_replication ----------------+------------------------------------------------+------------------------------------------------+---------------------- - test_ddl_only | DROP TABLE duper.man; | DROP TABLE duper.man; | t - test_ddl_only | DROP TABLE super.man CASCADE; | DROP TABLE super.man CASCADE; | f - test_ddl_only | ALTER TABLE duper.man ADD COLUMN foo text; | ALTER TABLE duper.man ADD COLUMN foo text; | t - test_ddl_only | ALTER TABLE super.man ADD COLUMN foo text; | ALTER TABLE super.man ADD COLUMN foo text; | f - test_ddl_only | CREATE TABLE duper.man(id serial primary key); | CREATE TABLE duper.man(id serial primary key); | t - test_ddl_only | CREATE SCHEMA duper; | CREATE SCHEMA duper; | t - test_ddl_only | CREATE TABLE super.man(id serial primary key); | CREATE TABLE super.man(id serial primary key); | f - test_ddl_only | CREATE SCHEMA super; | CREATE SCHEMA super; | f - test4 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f - test3 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f + set_name | ddl_sql_raw | ddl_sql_sent | ddl_only_replication +---------------+------------------------------------------------+-------------------------------------------------+---------------------- + test_ddl_only | DROP TABLE duper.man; | DROP TABLE duper.man; | t + test_ddl_only | DROP TABLE super.man CASCADE; | DROP TABLE super.man CASCADE; | f + test_ddl_only | ALTER TABLE duper.man ADD COLUMN foo text; | ALTER TABLE duper.man ADD COLUMN foo text; | t + test_ddl_only | ALTER TABLE super.man ADD COLUMN foo text; | ALTER TABLE super.man ADD COLUMN foo text; | f + test_ddl_only | CREATE TABLE duper.man(id serial primary key); | CREATE TABLE duper.man (id serial PRIMARY KEY); | t + test_ddl_only | CREATE SCHEMA duper; | CREATE SCHEMA duper; | t + test_ddl_only | CREATE TABLE super.man(id serial primary key); | CREATE TABLE super.man (id serial PRIMARY KEY); | f + test_ddl_only | CREATE SCHEMA super; | CREATE SCHEMA super; | f + test4 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f + test3 | CREATE SCHEMA bla; | CREATE SCHEMA bla; | f (10 rows) diff --git a/expected/52_sub_retries.out b/expected/52_sub_retries.out index c6c9a16..46554ee 100644 --- a/expected/52_sub_retries.out +++ b/expected/52_sub_retries.out @@ -2,36 +2,36 @@ --If adding new tests, it is best to keep this file as the last test before cleanup. SET client_min_messages = warning; SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(message::text, 'p_pid := (\d+)', 'p_pid := ?'), 'p_provider_name := (NULL|''\w+'')', 'p_provider_name := ?'), 'p_driver := (''\w+'')', 'p_driver := ?') as message FROM all_queues() WHERE NOT message::text LIKE '%notify_subscription_refresh%' ORDER BY queued_at; - pubnames | message_type | message ------------------------+--------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + pubnames | message_type | message +-----------------------+--------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER VIEW fooview RENAME TO barview;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -60,22 +60,22 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -84,22 +84,22 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS INT AS\n$BODY$\nSELECT 1;\n$BODY$\nLANGUAGE SQL STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO current_user;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO current_user;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO current_user;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE FUNCTION foobar.foo() RETURNS int AS $$\nSELECT 1;\n$$ LANGUAGE sql STABLE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER FUNCTION foobar.foo() OWNER TO CURRENT_USER;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -108,14 +108,14 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP FUNCTION foobar.foo();$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP FUNCTION foobar.foo();$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP FUNCTION foobar.foo();\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS\nSELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'fooview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW foobar.fooview AS SELECT 1 AS myfield;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW foobar.fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER VIEW foobar.fooview RENAME TO barview;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'barview',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER VIEW foobar.fooview RENAME TO barview;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER VIEW foobar.fooview RENAME TO barview;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -172,12 +172,12 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foobar.foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ CREATE TABLE foobar.foo(id int primary key); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ CREATE TABLE foobar.foo(id int primary key); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -190,48 +190,48 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo, foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo, foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo, foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo, foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo, foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id SERIAL PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id SERIAL PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id SERIAL PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id INT REFERENCES foo(id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN foo_id int REFERENCES foo (id);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -256,34 +256,34 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$/***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n /***\nIn default schema\n**/\nCREATE TABLE foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo(id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE foobar.foo ADD COLUMN bla text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := 'foobar',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE foobar.foo ADD COLUMN bla text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE foobar.foo ADD COLUMN bla text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -296,14 +296,14 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo(id int primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo(id int primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo(id int primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS\nSELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE viewer.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE viewer.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE viewer.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'viewer',\n p_relname := 'vw_foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP VIEW viewer.vw_foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP VIEW viewer.vw_foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP VIEW viewer.vw_foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP VIEW viewer.vw_foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -320,38 +320,38 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial primary key, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial primary key, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial primary key, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial primary key, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial primary key, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial primary key, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial primary key, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial primary key, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier TEXT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier TEXT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier TEXT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy to happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy to happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy to happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.foo (id serial PRIMARY KEY, foo text, bar text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD COLUMN happy text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD COLUMN happy text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD COLUMN happy text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar ADD COLUMN happier text;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'bar',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar ADD COLUMN happier text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar ADD COLUMN happier text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy TO happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN happy TO happyz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME COLUMN happy TO happyz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo ADD CONSTRAINT bla CHECK (true);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla to blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.foo RENAME CONSTRAINT bla TO blaz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'foo',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.foo RENAME COLUMN id TO id_2;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -377,10 +377,10 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.bar RENAME TO barz;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar RENAME TO barz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.bar RENAME TO barz;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.bar RENAME TO barz;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS TRIGGER AS $BODY$\nBEGIN\nRETURN NULL;\nEND;\n$BODY$\nLANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 11,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE OR REPLACE FUNCTION noop() RETURNS trigger AS $$\nBEGIN\nRETURN NULL;\nEND;\n$$ LANGUAGE plpgsql;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz DISABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz DISABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -390,16 +390,16 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ENABLE TRIGGER noop;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ENABLE TRIGGER noop;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ENABLE TRIGGER noop;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ENABLE TRIGGER noop;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id INT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id INT;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id INT;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 16,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'barz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.barz ADD COLUMN foo_id int REFERENCES special.fooz (id_2);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {my_special_tables_1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['my_special_tables_1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 15,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD COLUMN bar_id int;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id int;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD COLUMN bar_id int;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD COLUMN bar_id int;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'special',\n p_relname := 'fooz',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -416,10 +416,10 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial primary key);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -429,9 +429,9 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA bla;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA bla;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA bla;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA bla;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA super;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA super;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE super.man(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE super.man(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE super.man (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE super.man (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA duper;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE SCHEMA duper;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE duper.man(id serial primary key);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE duper.man(id serial primary key);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE duper.man (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n CREATE TABLE duper.man (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'super',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE super.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE super.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE duper.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE duper.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE super.man CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE super.man CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " diff --git a/expected/53_1_5_features.out b/expected/53_1_5_features.out index 22120c2..d25cf5f 100644 --- a/expected/53_1_5_features.out +++ b/expected/53_1_5_features.out @@ -17,9 +17,9 @@ SET search_path TO public; SET ROLE test_pgl_ddl_deploy; CREATE TABLE foo(id serial primary key, bla int); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------------+--------------------------------------------------- - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------------+---------------------------------------------------- + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); (1 row) GRANT SELECT ON foo TO PUBLIC; @@ -27,10 +27,10 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (2 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); @@ -40,12 +40,12 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (4 rows) SELECT * FROM pgl_ddl_deploy.unhandled; @@ -73,13 +73,13 @@ SELECT pgl_ddl_deploy.deploy(id) FROM pgl_ddl_deploy.set_configs WHERE set_name SET ROLE test_pgl_ddl_deploy; CREATE TABLE foo(id serial primary key, bla int); SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+---------------------------------------------------+--------------------------------------------------- - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------------------------------+---------------------------------------------------- + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); (5 rows) GRANT SELECT ON foo TO PUBLIC; @@ -87,14 +87,14 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (6 rows) INSERT INTO foo (bla) VALUES (1),(2),(3); @@ -104,16 +104,16 @@ SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.include_everything FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id ORDER BY e.id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent | include_everything -----------+---------------------------------------------------+---------------------------------------------------+-------------------- - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f - test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f - test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE INSERT ON foo FROM PUBLIC; | t - test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT SELECT ON foo TO PUBLIC; | t - test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo(id serial primary key, bla int); | f + set_name | ddl_sql_raw | ddl_sql_sent | include_everything +----------+---------------------------------------------------+----------------------------------------------------+-------------------- + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f + test1 | DROP TABLE foo CASCADE; | DROP TABLE foo CASCADE; | f + test1 | REVOKE INSERT ON foo FROM PUBLIC; | REVOKE insert ON foo FROM public; | t + test1 | GRANT SELECT ON foo TO PUBLIC; | GRANT select ON foo TO public; | t + test1 | CREATE TABLE foo(id serial primary key, bla int); | CREATE TABLE foo (id serial PRIMARY KEY, bla int); | f (8 rows) SELECT * FROM pgl_ddl_deploy.unhandled; diff --git a/expected/56_1_6_features.out b/expected/56_1_6_features.out index 2d6fe04..bcc1071 100644 --- a/expected/56_1_6_features.out +++ b/expected/56_1_6_features.out @@ -58,14 +58,3 @@ In <= 1.5, returned this: {"DROP SCHEMA","DROP TABLE","DROP FUNCTION","DROP TYPE","DROP VIEW","DROP SEQUENCE"} (1 row) */ -SET client_min_messages TO warning; -DROP OWNED BY test_pgl_ddl_deploy; -DROP ROLE test_pgl_ddl_deploy; -DROP ROLE unpriv; -DROP EXTENSION pgl_ddl_deploy CASCADE; -DROP EXTENSION IF EXISTS pglogical CASCADE; -DROP SCHEMA IF EXISTS pglogical CASCADE; -DROP TABLE IF EXISTS tmp_objs; -DROP SCHEMA IF EXISTS special CASCADE; -DROP SCHEMA IF EXISTS bla CASCADE; -DROP SCHEMA IF EXISTS pgl_ddl_deploy CASCADE; diff --git a/expected/57_2_4_features.out b/expected/57_2_4_features.out new file mode 100644 index 0000000..7e41ab6 --- /dev/null +++ b/expected/57_2_4_features.out @@ -0,0 +1,61 @@ +SET client_min_messages = warning; +CREATE PUBLICATION test_indexes_yes; +CREATE PUBLICATION test_indexes_no; +INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_schema_regex, lock_safe_deployment, allow_multi_statements, include_indexes) +VALUES ('test_indexes_yes', '^yindex.*', true, true, true); +INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_schema_regex, lock_safe_deployment, allow_multi_statements, include_indexes) +VALUES ('test_indexes_no', '^nindex.*', true, true, false); +SELECT pgl_ddl_deploy.deploy('test_indexes_yes'); + deploy +-------- + t +(1 row) + +SELECT pgl_ddl_deploy.deploy('test_indexes_no'); + deploy +-------- + t +(1 row) + +CREATE SCHEMA yindex; +CREATE TABLE yindex.widgets(id serial primary key, type varchar); +CREATE SCHEMA nindex; +CREATE TABLE nindex.widgets(id serial primary key, type varchar); +CREATE INDEX yindex_widgets_type_idx ON yindex.widgets(type); +CREATE INDEX CONCURRENTLY nindex_widgets_type_id_idx ON yindex.widgets(type, id); +CREATE INDEX nindex_widgets_type_idx ON nindex.widgets(type); +DROP TABLE yindex.widgets CASCADE; +DROP TABLE nindex.widgets CASCADE; +-- We expect to see index events for yindex.widgets but not for nindex.widgets +SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.ddl_only_replication +FROM pgl_ddl_deploy.events e +INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id +ORDER BY e.id DESC LIMIT 10; + set_name | ddl_sql_raw | ddl_sql_sent | ddl_only_replication +------------------+-----------------------------------------------------------------------------------+-------------------------------------------------------------------------------------+---------------------- + test_indexes_no | DROP TABLE nindex.widgets CASCADE; | DROP TABLE nindex.widgets CASCADE; | f + test_indexes_yes | DROP TABLE yindex.widgets CASCADE; | DROP TABLE yindex.widgets CASCADE; | f + test_indexes_yes | CREATE INDEX CONCURRENTLY nindex_widgets_type_id_idx ON yindex.widgets(type, id); | CREATE INDEX nindex_widgets_type_id_idx ON yindex.widgets USING btree (type, id); | f + test_indexes_yes | CREATE INDEX yindex_widgets_type_idx ON yindex.widgets(type); | CREATE INDEX yindex_widgets_type_idx ON yindex.widgets USING btree (type); | f + test_indexes_no | CREATE TABLE nindex.widgets(id serial primary key, type varchar); | CREATE TABLE nindex.widgets (id serial PRIMARY KEY, type varchar); | f + test_indexes_no | CREATE SCHEMA nindex; | CREATE SCHEMA nindex; | f + test_indexes_yes | CREATE TABLE yindex.widgets(id serial primary key, type varchar); | CREATE TABLE yindex.widgets (id serial PRIMARY KEY, type varchar); | f + test_indexes_yes | CREATE SCHEMA yindex; | CREATE SCHEMA yindex; | f + testspecial | CREATE FUNCTION special.do_replicate_me() +| CREATE FUNCTION special.do_replicate_me() RETURNS int AS $$SELECT 1$$ LANGUAGE sql; | f + | RETURNS INT +| | + | AS 'SELECT 1' +| | + | LANGUAGE SQL; | | + testspecial | CREATE TABLE special.bar (id serial primary key, super text, man text); | CREATE TABLE special.bar (id serial PRIMARY KEY, super text, man text); | f +(10 rows) + +SET client_min_messages TO warning; +DROP OWNED BY test_pgl_ddl_deploy; +DROP ROLE test_pgl_ddl_deploy; +DROP ROLE unpriv; +DROP EXTENSION pgl_ddl_deploy CASCADE; +DROP EXTENSION IF EXISTS pglogical CASCADE; +DROP SCHEMA IF EXISTS pglogical CASCADE; +DROP TABLE IF EXISTS tmp_objs; +DROP SCHEMA IF EXISTS special CASCADE; +DROP SCHEMA IF EXISTS bla CASCADE; +DROP SCHEMA IF EXISTS pgl_ddl_deploy CASCADE; diff --git a/expected/57_native_features.out b/expected/99_native_features.out similarity index 100% rename from expected/57_native_features.out rename to expected/99_native_features.out diff --git a/functions/rewrite_transaction_safe.sql b/functions/rewrite_transaction_safe.sql new file mode 100644 index 0000000..3231ffe --- /dev/null +++ b/functions/rewrite_transaction_safe.sql @@ -0,0 +1,6 @@ +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rewrite_transaction_safe(p_sql text) + RETURNS text + LANGUAGE c + STRICT +AS '$libdir/pgl_ddl_deploy', $function$rewrite_transaction_safe$function$ +; \ No newline at end of file diff --git a/functions/set_tag_defaults.sql b/functions/set_tag_defaults.sql index 9f271b9..8cf49ac 100644 --- a/functions/set_tag_defaults.sql +++ b/functions/set_tag_defaults.sql @@ -5,9 +5,15 @@ AS $function$ BEGIN IF NEW.create_tags IS NULL THEN NEW.create_tags = CASE WHEN NEW.include_only_repset_tables THEN pgl_ddl_deploy.standard_repset_only_tags() ELSE pgl_ddl_deploy.standard_create_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.create_tags = NEW.create_tags || '{"CREATE INDEX","ALTER INDEX"}'::TEXT[]; + END IF; END IF; IF NEW.drop_tags IS NULL THEN NEW.drop_tags = CASE WHEN NEW.include_only_repset_tables THEN NULL ELSE pgl_ddl_deploy.standard_drop_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.drop_tags = NEW.drop_tags || '{"DROP INDEX"}'::TEXT[]; + END IF; END IF; RETURN NEW; END; diff --git a/pgl_ddl_deploy--2.3--2.4.sql b/pgl_ddl_deploy--2.3--2.4.sql new file mode 100644 index 0000000..fbbdd95 --- /dev/null +++ b/pgl_ddl_deploy--2.3--2.4.sql @@ -0,0 +1,752 @@ +/* pgl_ddl_deploy--2.3--2.4.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_indexes BOOLEAN NOT NULL DEFAULT FALSE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rewrite_transaction_safe(p_sql text) + RETURNS text + LANGUAGE c + STRICT +AS '$libdir/pgl_ddl_deploy', $function$rewrite_transaction_safe$function$ +; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.set_tag_defaults() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN +IF NEW.create_tags IS NULL THEN + NEW.create_tags = CASE WHEN NEW.include_only_repset_tables THEN pgl_ddl_deploy.standard_repset_only_tags() ELSE pgl_ddl_deploy.standard_create_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.create_tags = NEW.create_tags || '{"CREATE INDEX","ALTER INDEX"}'::TEXT[]; + END IF; +END IF; +IF NEW.drop_tags IS NULL THEN + NEW.drop_tags = CASE WHEN NEW.include_only_repset_tables THEN NULL ELSE pgl_ddl_deploy.standard_drop_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.drop_tags = NEW.drop_tags || '{"DROP INDEX"}'::TEXT[]; + END IF; +END IF; +RETURN NEW; +END; +$function$ +; + +CREATE OR REPLACE VIEW pgl_ddl_deploy.event_trigger_schema AS +WITH vars AS +(SELECT + sc.id, + set_name, + 'pgl_ddl_deploy.auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_function_name, + 'auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_trigger_name, + 'auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_trigger_name, + 'auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_trigger_name, + include_schema_regex, + include_only_repset_tables, + create_tags, + drop_tags, + ddl_only_replication, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + sc.driver, + + /**** + These constants in DECLARE portion of all functions is identical and can be shared + */ + $BUILD$ + c_search_path TEXT = (SELECT current_setting('search_path')); + c_provider_name TEXT; + --TODO: How do I decide which replication set we care about? + v_pid INT = pg_backend_pid(); + v_rec RECORD; + v_ddl_sql_raw TEXT; + v_ddl_sql_sent TEXT; + v_full_ddl TEXT; + v_sql_tags TEXT[]; + v_cmd_rec RECORD; + v_subcmd_rec RECORD; + v_excluded_subcommands TEXT; + v_contains_any_valid_subcommand INT; + + /***** + We need to strip the DDL of: + 1. Transaction begin and commit, which cannot run inside plpgsql + *****/ + v_txid BIGINT; + v_ddl_length INT; + v_sql TEXT; + v_cmd_count INT; + v_match_count INT; + v_exclude_always_match_count INT; + v_nspname TEXT; + v_relname TEXT; + v_error TEXT; + v_error_detail TEXT; + v_context TEXT; + v_excluded_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_exception_msg TEXT = 'Deployment exception logged in pgl_ddl_deploy.exceptions'; + + --Configurable options in function setup + c_set_config_id INT = $BUILD$||sc.id::TEXT||$BUILD$; + -- Even though pglogical supports an array of sets, we only pipe DDL through one at a time + -- So c_set_name is a text not text[] data type. + c_set_name TEXT = '$BUILD$||set_name||$BUILD$'; + c_driver pgl_ddl_deploy.driver = '$BUILD$||sc.driver||$BUILD$'; + c_include_schema_regex TEXT = $BUILD$||COALESCE(''''||include_schema_regex||'''','NULL')||$BUILD$; + c_lock_safe_deployment BOOLEAN = $BUILD$||lock_safe_deployment||$BUILD$; + c_allow_multi_statements BOOLEAN = $BUILD$||allow_multi_statements||$BUILD$; + c_include_only_repset_tables BOOLEAN = $BUILD$||include_only_repset_tables||$BUILD$; + c_include_everything BOOLEAN = $BUILD$||include_everything||$BUILD$; + c_queue_subscriber_failures BOOLEAN = $BUILD$||queue_subscriber_failures||$BUILD$; + c_create_tags TEXT[] = '$BUILD$||create_tags::TEXT||$BUILD$'; + c_blacklisted_tags TEXT[] = '$BUILD$||blacklisted_tags::TEXT||$BUILD$'; + c_exclude_alter_table_subcommands TEXT[] = $BUILD$||COALESCE(quote_literal(exclude_alter_table_subcommands::TEXT),'NULL')||$BUILD$; + c_signal_blocking_subscriber_sessions TEXT = $BUILD$||COALESCE(quote_literal(signal_blocking_subscriber_sessions::TEXT),'NULL')||$BUILD$; + c_subscriber_lock_timeout INT = $BUILD$||COALESCE(subscriber_lock_timeout::TEXT,'NULL')||$BUILD$; + + --Constants based on configuration + c_exec_prefix TEXT =(CASE + WHEN c_lock_safe_deployment + THEN 'SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$' + ELSE '' + END); + c_exec_suffix TEXT = (CASE + WHEN c_lock_safe_deployment + THEN '$PGL_DDL_DEPLOY$);' + ELSE '' + END); + $BUILD$::TEXT AS declare_constants, + + $BUILD$ + --If there are any matches to our replication config, get the query + --This will either be sent, or logged at this point if not deployable + IF (c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0 THEN + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + v_txid = txid_current(); + END IF; + $BUILD$::TEXT AS shared_get_query, +/**** + This is the portion of the event trigger function that evaluates if SQL + is appropriate to propagate, and does propagate the event. It is shared + between the normal and drop event trigger functions. + */ + $BUILD$ + /**** + A multi-statement SQL command may fire this event trigger more than once + This check ensures the SQL is propagated only once, if at all + */ + IF EXISTS + (SELECT 1 FROM pgl_ddl_deploy.events + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + OR EXISTS + (SELECT 1 FROM pgl_ddl_deploy.unhandled + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + THEN + RETURN; + END IF; + + /**** + Get the command tags and reject blacklisted tags + */ + v_sql_tags:=(SELECT pgl_ddl_deploy.sql_command_tags(v_ddl_sql_raw)); + IF (SELECT c_blacklisted_tags && v_sql_tags) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_command_tags', + v_txid); + RETURN; + /**** + If we are not allowing multi-statements at all, reject + */ + ELSEIF (SELECT ARRAY[TG_TAG]::TEXT[] <> v_sql_tags WHERE NOT c_allow_multi_statements) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_multi_statement', + v_txid); + RETURN; + END IF; + + /**** + If this is an ALTER TABLE statement and we are excluding any subcommand tags, process now. + Note the following. + + Because there can be more than one subcommand, we have a limited ability + to filter out subcommands until such a time as we may have a mechanism for rebuilding only + the SQL we want. In other words, if we have one subcommand that we DO want (i.e. ADD COLUMN) + and one we don't want (i.e. REFERENCES) in the same SQL, and we are "excluding" the latter, + we can't do that exclusion safely because we WANT the ADD COLUMN statement. In such a case, + we are still going to allow the DDL to go through because it's better to break replication than + miss a column addition. + + But if the only subcommand is an excluded one, i.e. ADD CONSTRAINT, then we will indeed ignore + the DDL and the function will RETURN without executing replicate_ddl_command. + */ + IF TG_TAG = 'ALTER TABLE' AND c_exclude_alter_table_subcommands IS NOT NULL THEN + FOR v_cmd_rec IN + SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF pgl_ddl_deploy.get_command_type(v_cmd_rec.command) = 'alter table' THEN + WITH subcommands AS ( + SELECT subcommand, + c_exclude_alter_table_subcommands && ARRAY[subcommand] AS subcommand_is_excluded, + MAX(CASE WHEN c_exclude_alter_table_subcommands && ARRAY[subcommand] THEN 0 ELSE 1 END) OVER() AS contains_any_valid_subcommand + FROM unnest(pgl_ddl_deploy.get_altertable_subcmdinfo(v_cmd_rec.command)) AS subcommand + ) + + SELECT (SELECT string_agg(subcommand,', ') FROM subcommands WHERE subcommand_is_excluded), + (SELECT contains_any_valid_subcommand FROM subcommands LIMIT 1) + INTO v_excluded_subcommands, + v_contains_any_valid_subcommand; + IF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 0 THEN + RAISE LOG 'Not processing DDL due to excluded subcommand(s): %: %', v_excluded_subcommands, v_ddl_sql_raw; + RETURN; + ELSEIF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 1 THEN + RAISE WARNING $INNER_BLOCK$Filtering out more than one subcommand in one ALTER TABLE is not supported. + Allowing to proceed: Rejected: %, SQL: %$INNER_BLOCK$, v_excluded_subcommands, v_ddl_sql_raw; + END IF; + END IF; + END LOOP; + END IF; + + SELECT pgl_ddl_deploy.rewrite_transaction_safe(v_ddl_sql_raw) INTO v_ddl_sql_sent; + + --Get provider name, in order only to run command on a subscriber to this provider + c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); + + /* + Build replication DDL command which will conditionally run only on the subscriber + In other words, this MUST be a no-op on the provider + **Because the DDL has already run at this point (ddl_command_end)** + */ + v_full_ddl:=$INNER_BLOCK$ + --Be sure to use provider's search_path for SQL environment consistency + SET SEARCH_PATH TO $INNER_BLOCK$|| + CASE WHEN COALESCE(c_search_path,'') IN('','""') THEN quote_literal('') ELSE c_search_path END||$INNER_BLOCK$; + + $INNER_BLOCK$||c_exec_prefix||v_ddl_sql_sent||c_exec_suffix||$INNER_BLOCK$ + ; + $INNER_BLOCK$; + RAISE DEBUG 'v_full_ddl: %', v_full_ddl; + RAISE DEBUG 'c_set_config_id: %', c_set_config_id; + RAISE DEBUG 'c_set_name: %', c_set_name; + RAISE DEBUG 'c_driver: %', c_driver; + RAISE DEBUG 'v_ddl_sql_sent: %', v_ddl_sql_sent; + + v_sql:=$INNER_BLOCK$ + SELECT $BUILD$||CASE + WHEN sc.driver = 'native' + THEN 'pgl_ddl_deploy' + WHEN sc.driver = 'pglogical' + THEN 'pglogical' + ELSE 'ERROR-EXCEPTION' END||$BUILD$.replicate_ddl_command($REPLICATE_DDL_COMMAND$ + SELECT pgl_ddl_deploy.subscriber_command + ( + p_provider_name := $INNER_BLOCK$||COALESCE(quote_literal(c_provider_name), 'NULL')||$INNER_BLOCK$, + p_set_name := ARRAY[$INNER_BLOCK$||quote_literal(c_set_name)||$INNER_BLOCK$], + p_nspname := $INNER_BLOCK$||COALESCE(quote_literal(v_nspname), 'NULL')::TEXT||$INNER_BLOCK$, + p_relname := $INNER_BLOCK$||COALESCE(quote_literal(v_relname), 'NULL')::TEXT||$INNER_BLOCK$, + p_ddl_sql_sent := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_ddl_sql_sent||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_full_ddl := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_full_ddl||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_pid := $INNER_BLOCK$||v_pid::TEXT||$INNER_BLOCK$, + p_set_config_id := $INNER_BLOCK$||c_set_config_id::TEXT||$INNER_BLOCK$, + p_queue_subscriber_failures := $INNER_BLOCK$||c_queue_subscriber_failures||$INNER_BLOCK$, + p_signal_blocking_subscriber_sessions := $INNER_BLOCK$||COALESCE(quote_literal(c_signal_blocking_subscriber_sessions),'NULL')||$INNER_BLOCK$, + p_lock_timeout := $INNER_BLOCK$||COALESCE(c_subscriber_lock_timeout, 3000)||$INNER_BLOCK$, + p_driver := $INNER_BLOCK$||quote_literal(c_driver)||$INNER_BLOCK$ + ); + $REPLICATE_DDL_COMMAND$, + --Pipe this DDL command through chosen replication set + ARRAY['$INNER_BLOCK$||c_set_name||$INNER_BLOCK$']); + $INNER_BLOCK$; + + RAISE DEBUG 'v_sql: %', v_sql; + EXECUTE v_sql; + + INSERT INTO pgl_ddl_deploy.events + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + ddl_sql_sent, + txid) + VALUES + (c_set_config_id, + c_set_name, + v_pid, + current_timestamp, + v_ddl_sql_raw, + v_ddl_sql_sent, + v_txid); + $BUILD$::TEXT AS shared_deploy_logic, + $BUILD$ + ELSEIF (v_match_count > 0 AND v_cmd_count <> v_match_count) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'mixed_objects', + v_txid); + $BUILD$::TEXT AS shared_mixed_obj_logic, + $BUILD$ + -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + $BUILD$::TEXT AS dropped_objects_query, + + $BUILD$ + /** + Catch any exceptions and log in a local table + As a safeguard, if even the exception handler fails, exit cleanly but add a server log message + **/ + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + v_context = PG_EXCEPTION_CONTEXT, + v_error = MESSAGE_TEXT, + v_error_detail = PG_EXCEPTION_DETAIL; + BEGIN + INSERT INTO pgl_ddl_deploy.exceptions (set_config_id, set_name, pid, executed_at, ddl_sql, err_msg, err_state) + VALUES (c_set_config_id, c_set_name, v_pid, current_timestamp, v_sql, format('%s %s %s', v_error, v_context, v_error_detail), SQLSTATE); + RAISE WARNING '% (%: % - %)', c_exception_msg, v_error, v_context, v_error_detail; + --No matter what, don't let this function block any DDL + EXCEPTION WHEN OTHERS THEN + RAISE WARNING 'Unhandled exception % %', SQLERRM, SQLSTATE; + END; + $BUILD$::TEXT AS shared_exception_handler, + + $BUILD$ + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* c_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = c_set_name + AND rsr.relid = c.oid + AND rsr.driver = c_driver) + $BUILD$::TEXT AS shared_repl_set_tables, + + $BUILD$ + SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name ~* c_include_schema_regex + AND schema_name !~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_include_schema_regex + AND object_identity !~* c_exclude_always) + ) + ) + OR + --include_only_repset_tables usage: + ( + ($BUILD$||include_only_repset_tables||$BUILD$) AND + (EXISTS + ( + SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.relid = c.objid + AND c.object_type in('table','table column','table constraint') + AND rsr.name = '$BUILD$||sc.set_name||$BUILD$' + AND rsr.driver = '$BUILD$||sc.driver||$BUILD$' + ) + ) + ) + THEN 1 + ELSE 0 END) AS match_count, + SUM(CASE + WHEN + --include_everything usage still excludes exclude_always regex: + ( + ($BUILD$||include_everything||$BUILD$) AND + ( + (schema_name ~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_exclude_always) + ) + ) + THEN 1 + ELSE 0 END) AS exclude_always_match_count + $BUILD$::TEXT AS shared_match_count +FROM pgl_ddl_deploy.rep_set_wrapper() rs +INNER JOIN pgl_ddl_deploy.set_configs sc ON sc.set_name = rs.name AND sc.driver = rs.driver +) + +, build AS ( +SELECT + id, + set_name, + include_schema_regex, + include_only_repset_tables, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + auto_replication_create_function_name, + auto_replication_drop_function_name, + auto_replication_unsupported_function_name, + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name, + +CASE WHEN driver = 'pglogical' THEN '--no-op pglogical diver'::TEXT +WHEN driver = 'native' THEN $BUILD$ +DO $$ +BEGIN + +IF NOT EXISTS (SELECT 1 +FROM pg_publication_tables +WHERE pubname = '$BUILD$||set_name||$BUILD$' +AND schemaname = 'pgl_ddl_deploy' +AND tablename = 'queue') THEN + ALTER PUBLICATION $BUILD$||quote_ident(set_name)||$BUILD$ + ADD TABLE pgl_ddl_deploy.queue; +END IF; + +END$$; +$BUILD$ +END AS add_queue_table_to_replication, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$ || auto_replication_create_function_name || $BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , MAX(c.schema_name) + , MAX(cl.relname) + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_nspname, v_relname + FROM pg_event_trigger_ddl_commands() c + LEFT JOIN LATERAL + (SELECT cl.relname + FROM pg_class cl + WHERE cl.oid = c.objid + AND c.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') + -- There should only be one table modified per event trigger + -- At least that's the best we will do now + LIMIT 1) cl ON TRUE; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_cmd_count = v_match_count)) + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension + FROM pg_event_trigger_ddl_commands(); + + /** + Add table to replication set immediately, if required, and only if the set_config includes CREATE TABLE. + We do not filter to tags here, because of possibility of multi-statement SQL. + Optional ddl_only_replication will never auto-add tables to replication because the + purpose is to only replicate keep the structure synchronized on the subscriber with no data. + **/ + IF c_create_tags && '{"CREATE TABLE"}' AND NOT $BUILD$||include_only_repset_tables||$BUILD$ AND NOT $BUILD$||ddl_only_replication||$BUILD$ THEN + PERFORM pgl_ddl_deploy.add_table_to_replication( + p_driver:=c_driver + ,p_set_name:=c_set_name + ,p_relation:=c.oid + ,p_synchronize_data:=false + ) + $BUILD$||shared_repl_set_tables||$BUILD$; + END IF; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$::TEXT +END AS auto_replication_function, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_drop_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name !~* '^(pg_catalog|pg_toast)$' + AND schema_name !~* c_include_schema_regex) + OR (object_type = 'schema' + AND object_identity !~* '^(pg_catalog|pg_toast)$' + AND object_identity !~* c_include_schema_regex) + ) + ) + --include_only_repset_tables cannot be used with DROP because + --the objects no longer exist to be checked: + THEN 1 + ELSE 0 END) AS excluded_count + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_excluded_count + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_excluded_count = 0)) + + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + TG_TAG, + object_type, + schema_name, + object_identity, + NULL + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_drop_function, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_unsupported_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + INTO v_cmd_count, v_match_count, v_exclude_always_match_count + FROM pg_event_trigger_ddl_commands() c; + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0) + THEN + + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'unsupported_command', + v_txid); + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_unsupported_function, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(create_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$ || auto_replication_create_function_name || $BUILD$(); +$BUILD$::TEXT +END AS auto_replication_trigger, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ON sql_drop +WHEN TAG IN('$BUILD$||array_to_string(drop_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$||auto_replication_drop_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_drop_trigger, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(pgl_ddl_deploy.unsupported_tags(),$$','$$)||$BUILD$') +EXECUTE PROCEDURE $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_unsupported_trigger, + +$BUILD$ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs (obj_type, obj_name) AS ( +VALUES +('EVENT TRIGGER','$BUILD$||auto_replication_create_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_drop_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_unsupported_trigger_name||$BUILD$'), +('FUNCTION','$BUILD$||auto_replication_create_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_drop_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_unsupported_function_name||$BUILD$()') +); + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; +DROP EVENT TRIGGER IF EXISTS $BUILD$||auto_replication_create_trigger_name||', '||auto_replication_drop_trigger_name||', '||auto_replication_unsupported_trigger_name||$BUILD$; +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_create_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_drop_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$ + AS undeploy_sql +FROM vars) + +SELECT + b.id, + b.set_name, + b.include_schema_regex, + b.include_only_repset_tables, + b.include_everything, + b.signal_blocking_subscriber_sessions, + b.subscriber_lock_timeout, + b.auto_replication_create_function_name, + b.auto_replication_drop_function_name, + b.auto_replication_unsupported_function_name, + b.auto_replication_create_trigger_name, + b.auto_replication_drop_trigger_name, + b.auto_replication_unsupported_trigger_name, + b.auto_replication_function, + b.auto_replication_drop_function, + b.auto_replication_unsupported_function, + b.auto_replication_trigger, + b.auto_replication_drop_trigger, + b.auto_replication_unsupported_trigger, + b.undeploy_sql, + b.undeploy_sql|| + b.add_queue_table_to_replication||$BUILD$ + $BUILD$||auto_replication_function||$BUILD$ + $BUILD$||auto_replication_drop_function||$BUILD$ + $BUILD$||auto_replication_unsupported_function||$BUILD$ + $BUILD$||auto_replication_trigger||$BUILD$ + $BUILD$||auto_replication_drop_trigger||$BUILD$ + $BUILD$||auto_replication_unsupported_trigger||$BUILD$ + SELECT pgl_ddl_deploy.add_ext_object(obj_type, obj_name) + FROM tmp_objs; + $BUILD$ AS deploy_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ DISABLE; + $BUILD$ AS disable_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ENABLE; + $BUILD$ AS enable_sql, + EXISTS (SELECT 1 + FROM pg_event_trigger + WHERE evtname IN( + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name + ) + AND evtenabled IN('O','R','A') + ) AS is_deployed +FROM build b; + + diff --git a/pgl_ddl_deploy--2.4.sql b/pgl_ddl_deploy--2.4.sql new file mode 100644 index 0000000..70fb847 --- /dev/null +++ b/pgl_ddl_deploy--2.4.sql @@ -0,0 +1,5918 @@ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +CREATE FUNCTION pgl_ddl_deploy.sql_command_tags(p_sql TEXT) +RETURNS TEXT[] AS +'MODULE_PATHNAME', 'sql_command_tags' +LANGUAGE C VOLATILE STRICT; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.add_ext_object + (p_type text + , p_full_obj_name text) +RETURNS VOID AS +$BODY$ +BEGIN +PERFORM pgl_ddl_deploy.toggle_ext_object(p_type, p_full_obj_name, 'ADD'); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.drop_ext_object + (p_type text + , p_full_obj_name text) +RETURNS VOID AS +$BODY$ +BEGIN +PERFORM pgl_ddl_deploy.toggle_ext_object(p_type, p_full_obj_name, 'DROP'); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.toggle_ext_object + (p_type text + , p_full_obj_name text + , p_toggle text) +RETURNS VOID AS +$BODY$ +DECLARE + c_valid_types TEXT[] = ARRAY['EVENT TRIGGER','FUNCTION','VIEW']; + c_valid_toggles TEXT[] = ARRAY['ADD','DROP']; +BEGIN + +IF NOT (SELECT ARRAY[p_type] && c_valid_types) THEN + RAISE EXCEPTION 'Must pass one of % as 1st arg.', array_to_string(c_valid_types); +END IF; + +IF NOT (SELECT ARRAY[p_toggle] && c_valid_toggles) THEN + RAISE EXCEPTION 'Must pass one of % as 3rd arg.', array_to_string(c_valid_toggles); +END IF; + +EXECUTE 'ALTER EXTENSION pgl_ddl_deploy '||p_toggle||' '||p_type||' '||p_full_obj_name; + +EXCEPTION + WHEN undefined_function THEN + RETURN; + WHEN undefined_object THEN + RETURN; + WHEN object_not_in_prerequisite_state THEN + RETURN; +END; +$BODY$ +LANGUAGE plpgsql; +CREATE FUNCTION pgl_ddl_deploy.exclude_regex() +RETURNS TEXT AS +$BODY$ +SELECT '^(pg_catalog|information_schema|pg_temp|pg_toast|pgl_ddl_deploy|pglogical).*'::TEXT; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +CREATE FUNCTION pgl_ddl_deploy.blacklisted_tags() +RETURNS TEXT[] AS +$BODY$ +SELECT '{ + INSERT, + UPDATE, + DELETE, + TRUNCATE, + SELECT, + ROLLBACK, + "CREATE EXTENSION", + "ALTER EXTENSION", + "DROP EXTENSION"}'::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +CREATE TABLE pgl_ddl_deploy.set_configs ( + set_name NAME PRIMARY KEY, + include_schema_regex TEXT NOT NULL, + lock_safe_deployment BOOLEAN DEFAULT FALSE NOT NULL, + allow_multi_statements BOOLEAN DEFAULT TRUE NOT NULL, + CONSTRAINT valid_regex CHECK (CASE WHEN regexp_replace('',include_schema_regex,'') = '' THEN TRUE ELSE FALSE END) + ); + +SELECT pg_catalog.pg_extension_config_dump('pgl_ddl_deploy.set_configs', ''); + +CREATE TABLE pgl_ddl_deploy.events ( + id SERIAL PRIMARY KEY, + set_name NAME, + pid INT, + executed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + ddl_sql_raw TEXT, + ddl_sql_sent TEXT, + txid BIGINT + ); + +CREATE UNIQUE INDEX ON pgl_ddl_deploy.events (set_name, pid, txid, md5(ddl_sql_raw)); + +CREATE TABLE pgl_ddl_deploy.exceptions ( + id SERIAL PRIMARY KEY, + set_name NAME, + pid INT, + executed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + ddl_sql TEXT, + err_msg TEXT, + err_state TEXT); + +CREATE TABLE pgl_ddl_deploy.unhandled ( + id SERIAL PRIMARY KEY, + set_name NAME, + pid INT, + executed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + ddl_sql_raw TEXT, + command_tag TEXT, + reason TEXT, + txid BIGINT, + CONSTRAINT valid_reason CHECK (reason IN('mixed_objects','rejected_command_tags','rejected_multi_statement','unsupported_command')) + ); + +CREATE UNIQUE INDEX ON pgl_ddl_deploy.unhandled (set_name, pid, txid, md5(ddl_sql_raw)); + +CREATE FUNCTION pgl_ddl_deploy.log_unhandled +(p_set_name TEXT, + p_pid INT, + p_ddl_sql_raw TEXT, + p_command_tag TEXT, + p_reason TEXT, + p_txid BIGINT) +RETURNS VOID AS +$BODY$ +DECLARE + c_unhandled_msg TEXT = 'Unhandled deployment logged in pgl_ddl_deploy.unhandled'; +BEGIN +INSERT INTO pgl_ddl_deploy.unhandled + (set_name, + pid, + executed_at, + ddl_sql_raw, + command_tag, + reason, + txid) +VALUES + (p_set_name, + p_pid, + current_timestamp, + p_ddl_sql_raw, + p_command_tag, + p_reason, + p_txid); +RAISE WARNING '%', c_unhandled_msg; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE TABLE pgl_ddl_deploy.subscriber_logs ( + id SERIAL PRIMARY KEY, + set_name NAME, + provider_pid INT, + subscriber_pid INT, + executed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, + ddl_sql TEXT); + +CREATE TABLE pgl_ddl_deploy.commands ( + id SERIAL PRIMARY KEY, + set_name NAME, + pid INT, + txid BIGINT, + classid Oid, + objid Oid, + objsubid integer, + command_tag text, + object_type text, + schema_name text, + object_identity text, + in_extension bool); + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.lock_safe_executor(p_sql TEXT) +RETURNS VOID AS $BODY$ +BEGIN +SET lock_timeout TO '10ms'; +LOOP + BEGIN + EXECUTE p_sql; + EXIT; + EXCEPTION + WHEN lock_not_available + THEN RAISE WARNING 'Could not obtain immediate lock for SQL %, retrying', p_sql; + PERFORM pg_sleep(3); + WHEN OTHERS THEN + RAISE; + END; +END LOOP; +END; +$BODY$ +LANGUAGE plpgsql; + + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deploy(p_set_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_deployable BOOLEAN; + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.deployment_check(p_set_name) INTO v_deployable; + IF v_deployable THEN + SELECT pgl_ddl_deploy.schema_execute(p_set_name, 'deploy_sql') INTO v_result; + RETURN v_result; + ELSE + RETURN v_deployable; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.enable(p_set_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_deployable BOOLEAN; + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.deployment_check(p_set_name) INTO v_deployable; + IF v_deployable THEN + SELECT pgl_ddl_deploy.schema_execute(p_set_name, 'enable_sql') INTO v_result; + RETURN v_result; + ELSE + RETURN v_deployable; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.disable(p_set_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.schema_execute(p_set_name, 'disable_sql') INTO v_result; + RETURN v_result; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.schema_execute(p_set_name text, p_field_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_in_sql TEXT; + v_out_sql TEXT; +BEGIN + v_in_sql = $$(SELECT $$||p_field_name||$$ + FROM pgl_ddl_deploy.event_trigger_schema + WHERE set_name = '$$||p_set_name||$$');$$; + EXECUTE v_in_sql INTO v_out_sql; + IF v_out_sql IS NULL THEN + RETURN FALSE; + ELSE + EXECUTE v_out_sql; + RETURN TRUE; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + + +GRANT USAGE ON SCHEMA pgl_ddl_deploy TO PUBLIC; +DO $$ BEGIN +IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pglogical') THEN +GRANT USAGE ON SCHEMA pglogical TO PUBLIC; REVOKE EXECUTE ON ALL FUNCTIONS IN SCHEMA pglogical FROM PUBLIC; +END IF; +IF EXISTS (SELECT 1 FROM pg_proc p INNER JOIN pg_namespace n ON n.oid = p.pronamespace WHERE proname = 'dependency_check_trigger' AND nspname = 'pglogical') THEN + GRANT EXECUTE ON FUNCTION pglogical.dependency_check_trigger() TO PUBLIC; +END IF; +IF EXISTS (SELECT 1 FROM pg_proc p INNER JOIN pg_namespace n ON n.oid = p.pronamespace WHERE proname = 'truncate_trigger_add' AND nspname = 'pglogical') THEN + GRANT EXECUTE ON FUNCTION pglogical.truncate_trigger_add() TO PUBLIC; +END IF; +END$$; +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.sql_command_tags(text) FROM PUBLIC; +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +/**** +We first need to drop existing event triggers and functions, because the naming convention is +changing + */ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs AS +WITH old_named_objects AS +(SELECT set_name, + + 'pgl_ddl_deploy.auto_replicate_ddl_'||set_name||'()' AS auto_replication_function_name, + 'pgl_ddl_deploy.auto_replicate_ddl_drop_'||set_name||'()' AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_replicate_ddl_unsupported_'||set_name||'()' AS auto_replication_unsupported_function_name, + 'auto_replicate_ddl_'||set_name AS auto_replication_trigger_name, + 'auto_replicate_ddl_drop_'||set_name AS auto_replication_drop_trigger_name, + 'auto_replicate_ddl_unsupported_'||set_name AS auto_replication_unsupported_trigger_name + +FROM pgl_ddl_deploy.set_configs) + +SELECT set_name, 'EVENT TRIGGER' AS obj_type, auto_replication_trigger_name AS obj_name FROM old_named_objects UNION ALL +SELECT set_name, 'EVENT TRIGGER' AS obj_type, auto_replication_drop_trigger_name AS obj_name FROM old_named_objects UNION ALL +SELECT set_name, 'EVENT TRIGGER' AS obj_type, auto_replication_unsupported_trigger_name AS obj_name FROM old_named_objects UNION ALL +SELECT set_name, 'FUNCTION' AS obj_type, auto_replication_function_name AS obj_name FROM old_named_objects UNION ALL +SELECT set_name, 'FUNCTION' AS obj_type, auto_replication_drop_function_name AS obj_name FROM old_named_objects UNION ALL +SELECT set_name, 'FUNCTION' AS obj_type, auto_replication_unsupported_function_name AS obj_name FROM old_named_objects +; + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; + +DO $BUILD$ +DECLARE + v_rec RECORD; + v_sql TEXT; +BEGIN + +FOR v_rec IN + SELECT * FROM tmp_objs WHERE obj_type = 'EVENT TRIGGER' +LOOP + +v_sql = $$DROP EVENT TRIGGER IF EXISTS $$||v_rec.obj_name||$$;$$; +EXECUTE v_sql; +RAISE WARNING 'Event trigger % dropped', v_rec.obj_name; + +END LOOP; + +FOR v_rec IN + SELECT * FROM tmp_objs WHERE obj_type = 'FUNCTION' +LOOP +v_sql = $$DROP FUNCTION IF EXISTS $$||v_rec.obj_name||$$;$$; +EXECUTE v_sql; +RAISE WARNING 'Function % dropped', v_rec.obj_name; + +END LOOP; + +FOR v_rec IN + SELECT DISTINCT set_name FROM tmp_objs +LOOP +RAISE WARNING $$Objects changed - you must manually re-deploy using pgl_ddl_deploy.deploy('%')$$, v_rec.set_name; +END LOOP; + +END +$BUILD$; + +--If you don't do this, it will be part of the extension! +DROP TABLE tmp_objs; + +CREATE FUNCTION pgl_ddl_deploy.standard_create_tags() +RETURNS TEXT[] AS +$BODY$ +SELECT '{ + "ALTER TABLE" + ,"CREATE SEQUENCE" + ,"ALTER SEQUENCE" + ,"CREATE SCHEMA" + ,"CREATE TABLE" + ,"CREATE FUNCTION" + ,"ALTER FUNCTION" + ,"CREATE TYPE" + ,"ALTER TYPE" + ,"CREATE VIEW" + ,"ALTER VIEW" + }'::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +CREATE FUNCTION pgl_ddl_deploy.standard_drop_tags() +RETURNS TEXT[] AS +$BODY$ +SELECT '{ + "DROP SCHEMA" + ,"DROP TABLE" + ,"DROP FUNCTION" + ,"DROP TYPE" + ,"DROP VIEW" + ,"DROP SEQUENCE" + }'::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +CREATE FUNCTION pgl_ddl_deploy.unsupported_tags() +RETURNS TEXT[] AS +$BODY$ +SELECT '{ + "CREATE TABLE AS" + ,"SELECT INTO" + }'::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN id SERIAL; +ALTER TABLE pgl_ddl_deploy.set_configs DROP CONSTRAINT set_configs_pkey; +ALTER TABLE pgl_ddl_deploy.set_configs ADD PRIMARY KEY (id); +ALTER TABLE pgl_ddl_deploy.commands ADD COLUMN set_config_id INT REFERENCES pgl_ddl_deploy.set_configs (id); +ALTER TABLE pgl_ddl_deploy.events ADD COLUMN set_config_id INT REFERENCES pgl_ddl_deploy.set_configs (id); +ALTER TABLE pgl_ddl_deploy.unhandled ADD COLUMN set_config_id INT REFERENCES pgl_ddl_deploy.set_configs (id); +ALTER TABLE pgl_ddl_deploy.exceptions ADD COLUMN set_config_id INT REFERENCES pgl_ddl_deploy.set_configs (id); + +ALTER EXTENSION pgl_ddl_deploy +DROP FUNCTION pgl_ddl_deploy.log_unhandled +(TEXT, + INT, + TEXT, + TEXT, + TEXT, + BIGINT); +DROP FUNCTION pgl_ddl_deploy.log_unhandled +(TEXT, + INT, + TEXT, + TEXT, + TEXT, + BIGINT); +CREATE FUNCTION pgl_ddl_deploy.log_unhandled +(p_set_config_id INT, + p_set_name TEXT, + p_pid INT, + p_ddl_sql_raw TEXT, + p_command_tag TEXT, + p_reason TEXT, + p_txid BIGINT) +RETURNS VOID AS +$BODY$ +DECLARE + c_unhandled_msg TEXT = 'Unhandled deployment logged in pgl_ddl_deploy.unhandled'; +BEGIN +INSERT INTO pgl_ddl_deploy.unhandled + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + command_tag, + reason, + txid) +VALUES + (p_set_config_id, + p_set_name, + p_pid, + current_timestamp, + p_ddl_sql_raw, + p_command_tag, + p_reason, + p_txid); +RAISE WARNING '%', c_unhandled_msg; +END; +$BODY$ +LANGUAGE plpgsql; + +--Allow specific tables or include regex +ALTER TABLE pgl_ddl_deploy.set_configs ALTER COLUMN include_schema_regex DROP NOT NULL; +ALTER TABLE pgl_ddl_deploy.set_configs DROP CONSTRAINT valid_regex; +ALTER TABLE pgl_ddl_deploy.set_configs ADD CONSTRAINT valid_regex CHECK (include_schema_regex IS NULL OR (CASE WHEN regexp_replace('',include_schema_regex,'') = '' THEN TRUE ELSE FALSE END)); +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_only_repset_tables BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE pgl_ddl_deploy.set_configs ADD CONSTRAINT repset_tables_or_regex_inclusion CHECK ((include_schema_regex IS NOT NULL AND NOT include_only_repset_tables) OR (include_only_repset_tables AND include_schema_regex IS NULL)); + +--Customize command tags +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN create_tags TEXT[]; +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN drop_tags TEXT[]; +UPDATE pgl_ddl_deploy.set_configs +SET create_tags = pgl_ddl_deploy.standard_create_tags(), + drop_tags = pgl_ddl_deploy.standard_drop_tags(); +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN blacklisted_tags TEXT[] DEFAULT pgl_ddl_deploy.blacklisted_tags(); + +--Allow failures +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN queue_subscriber_failures BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE pgl_ddl_deploy.set_configs ADD CONSTRAINT repset_tables_only_alter_table CHECK ((NOT include_only_repset_tables) OR (include_only_repset_tables AND create_tags = '{"ALTER TABLE"}' AND drop_tags IS NULL)); + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.unique_tags() +RETURNS TRIGGER AS +$BODY$ +BEGIN + IF EXISTS ( + SELECT 1 + FROM pgl_ddl_deploy.set_configs + WHERE id <> NEW.id + AND set_name = NEW.set_name + AND (create_tags && NEW.create_tags + OR drop_tags && NEW.drop_tags)) THEN + RAISE EXCEPTION $$Another set_config already exists for '%' with overlapping create_tags or drop_tags. + Command tags must only appear once per set_name even if using multiple set_configs. + $$, NEW.set_name; + END IF; + RETURN NEW; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE TRIGGER unique_tags +BEFORE INSERT OR UPDATE ON pgl_ddl_deploy.set_configs +FOR EACH ROW EXECUTE PROCEDURE pgl_ddl_deploy.unique_tags(); + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.set_tag_defaults() +RETURNS TRIGGER AS +$BODY$ +BEGIN +IF NEW.create_tags IS NULL THEN + NEW.create_tags = CASE WHEN NEW.include_only_repset_tables THEN '{"ALTER TABLE"}' ELSE pgl_ddl_deploy.standard_create_tags() END; +END IF; +IF NEW.drop_tags IS NULL THEN + NEW.drop_tags = CASE WHEN NEW.include_only_repset_tables THEN NULL ELSE pgl_ddl_deploy.standard_drop_tags() END; +END IF; +RETURN NEW; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE TRIGGER set_tag_defaults +BEFORE INSERT OR UPDATE ON pgl_ddl_deploy.set_configs +FOR EACH ROW EXECUTE PROCEDURE pgl_ddl_deploy.set_tag_defaults(); + +ALTER TABLE pgl_ddl_deploy.subscriber_logs + ADD COLUMN full_ddl_sql TEXT, + ADD COLUMN origin_subscriber_log_id INT NULL REFERENCES pgl_ddl_deploy.subscriber_logs(id), + ADD COLUMN next_subscriber_log_id INT NULL REFERENCES pgl_ddl_deploy.subscriber_logs(id), + ADD COLUMN provider_node_name TEXT, + ADD COLUMN provider_set_config_id INT, + ADD COLUMN executed_as_role TEXT DEFAULT current_role, + ADD COLUMN retrying BOOLEAN NOT NULL DEFAULT FALSE, + ADD COLUMN succeeded BOOLEAN NULL, + ADD COLUMN error_message TEXT; + +CREATE FUNCTION pgl_ddl_deploy.set_origin_subscriber_log_id() +RETURNS TRIGGER AS +$BODY$ +BEGIN +NEW.origin_subscriber_log_id = NEW.id; +RETURN NEW; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE TRIGGER set_origin_subscriber_log_id +BEFORE INSERT ON pgl_ddl_deploy.subscriber_logs +FOR EACH ROW WHEN (NEW.origin_subscriber_log_id IS NULL) +EXECUTE PROCEDURE pgl_ddl_deploy.set_origin_subscriber_log_id(); + +ALTER TABLE pgl_ddl_deploy.subscriber_logs ENABLE REPLICA TRIGGER set_origin_subscriber_log_id; + +CREATE UNIQUE INDEX unique_untried ON pgl_ddl_deploy.subscriber_logs (origin_subscriber_log_id) WHERE NOT succeeded AND next_subscriber_log_id IS NULL AND NOT retrying; +CREATE UNIQUE INDEX unique_retrying ON pgl_ddl_deploy.subscriber_logs (origin_subscriber_log_id) WHERE retrying; +CREATE UNIQUE INDEX unique_succeeded ON pgl_ddl_deploy.subscriber_logs (origin_subscriber_log_id) WHERE succeeded; + +CREATE FUNCTION pgl_ddl_deploy.fail_queued_attempt(p_subscriber_log_id INT, p_error_message TEXT) +RETURNS VOID AS +$BODY$ +DECLARE + v_new_subscriber_log_id INT; +BEGIN + +INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + subscriber_pid, + ddl_sql, + full_ddl_sql, + origin_subscriber_log_id, + provider_node_name, + provider_set_config_id, + executed_as_role, + error_message, + succeeded) +SELECT + set_name, + provider_pid, + pg_backend_pid(), + ddl_sql, + full_ddl_sql, + origin_subscriber_log_id, + provider_node_name, + provider_set_config_id, + executed_as_role, + p_error_message, + FALSE +FROM pgl_ddl_deploy.subscriber_logs +WHERE id = p_subscriber_log_id +RETURNING id INTO v_new_subscriber_log_id; + +UPDATE pgl_ddl_deploy.subscriber_logs +SET next_subscriber_log_id = v_new_subscriber_log_id +WHERE id = p_subscriber_log_id; + +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE FUNCTION pgl_ddl_deploy.retry_subscriber_log(p_subscriber_log_id INT) +RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_sql TEXT; + v_role TEXT; + v_return BOOLEAN; +BEGIN + IF (SELECT retrying FROM pgl_ddl_deploy.subscriber_logs + WHERE id = p_subscriber_log_id) = TRUE THEN + RAISE WARNING 'This subscriber_log_id is already executing. No action will be taken.'; + RETURN FALSE; + END IF; + + SELECT full_ddl_sql, executed_as_role + INTO v_sql, v_role + FROM pgl_ddl_deploy.subscriber_logs + WHERE id = p_subscriber_log_id; + + UPDATE pgl_ddl_deploy.subscriber_logs + SET retrying = TRUE + WHERE id = p_subscriber_log_id; + + BEGIN + /** + This needs to be a DO block because currently,the final SQL sent to subscriber is always within a DO block + */ + v_sql = $$ + DO $RETRY$ + BEGIN + + SET ROLE $$||quote_ident(v_role)||$$; + + $$||v_sql||$$ + + END$RETRY$; + $$; + EXECUTE v_sql; + RESET ROLE; + + WITH success AS ( + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + subscriber_pid, + ddl_sql, + full_ddl_sql, + origin_subscriber_log_id, + provider_node_name, + provider_set_config_id, + executed_as_role, + succeeded) + SELECT + set_name, + provider_pid, + pg_backend_pid(), + ddl_sql, + full_ddl_sql, + origin_subscriber_log_id, + provider_node_name, + provider_set_config_id, + executed_as_role, + TRUE + FROM pgl_ddl_deploy.subscriber_logs + WHERE id = p_subscriber_log_id + RETURNING * + ) + + UPDATE pgl_ddl_deploy.subscriber_logs + SET next_subscriber_log_id = (SELECT id FROM success) + WHERE id = p_subscriber_log_id; + + v_return = TRUE; + + EXCEPTION WHEN OTHERS THEN + PERFORM pgl_ddl_deploy.fail_queued_attempt(p_subscriber_log_id, SQLERRM); + v_return = FALSE; + END; + + UPDATE pgl_ddl_deploy.subscriber_logs + SET retrying = FALSE + WHERE id = p_subscriber_log_id; + + RETURN v_return; + +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE FUNCTION pgl_ddl_deploy.retry_all_subscriber_logs() +RETURNS BOOLEAN[] AS +$BODY$ +DECLARE + v_rec RECORD; + v_result BOOLEAN; + v_results BOOLEAN[]; +BEGIN + +FOR v_rec IN + SELECT + rq.id + FROM pgl_ddl_deploy.subscriber_logs rq + INNER JOIN pgl_ddl_deploy.subscriber_logs rqo ON rqo.id = rq.origin_subscriber_log_id + WHERE NOT rq.succeeded AND rq.next_subscriber_log_id IS NULL AND NOT rq.retrying + ORDER BY rqo.executed_at ASC, rqo.origin_subscriber_log_id ASC +LOOP + + SELECT pgl_ddl_deploy.retry_subscriber_log(v_rec.id) INTO v_result; + v_results = array_append(v_results, v_result); + IF NOT v_result THEN + RETURN v_results; + END IF; + +END LOOP; + +RETURN v_results; + +END; +$BODY$ +LANGUAGE plpgsql; + +--Allow a mechanism to mark unhandled and exceptions as resolved for monitoring purposes +ALTER TABLE pgl_ddl_deploy.unhandled ADD COLUMN resolved BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE pgl_ddl_deploy.unhandled ADD COLUMN resolved_notes TEXT NULL; +ALTER TABLE pgl_ddl_deploy.exceptions ADD COLUMN resolved BOOLEAN NOT NULL DEFAULT FALSE; +ALTER TABLE pgl_ddl_deploy.exceptions ADD COLUMN resolved_notes TEXT NULL; + +CREATE FUNCTION pgl_ddl_deploy.resolve_unhandled(p_unhandled_id INT, p_notes TEXT = NULL) +RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_row_count INT; +BEGIN + UPDATE pgl_ddl_deploy.unhandled + SET resolved = TRUE, + resolved_notes = p_notes + WHERE id = p_unhandled_id; + + GET DIAGNOSTICS v_row_count = ROW_COUNT; + RETURN (v_row_count > 0); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE FUNCTION pgl_ddl_deploy.resolve_exception(p_exception_id INT, p_notes TEXT = NULL) +RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_row_count INT; +BEGIN + UPDATE pgl_ddl_deploy.exceptions + SET resolved = TRUE, + resolved_notes = p_notes + WHERE id = p_exception_id; + + GET DIAGNOSTICS v_row_count = ROW_COUNT; + RETURN (v_row_count > 0); +END; +$BODY$ +LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check(p_set_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_set_config_id INT; + c_include_schema_regex TEXT; +BEGIN + +IF NOT EXISTS (SELECT 1 FROM pgl_ddl_deploy.set_configs WHERE set_name = p_set_name) THEN + RETURN FALSE; +END IF; + +--This check only applicable to non-include_only_repset_tables and sets using CREATE TABLE events +SELECT id, include_schema_regex +INTO c_set_config_id, c_include_schema_regex +FROM pgl_ddl_deploy.set_configs +WHERE set_name = p_set_name + AND NOT include_only_repset_tables + AND create_tags && '{"CREATE TABLE"}'::TEXT[]; + +RETURN pgl_ddl_deploy.deployment_check_count(c_set_config_id, p_set_name, c_include_schema_regex); + +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check(p_set_config_id int) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_set_config_id INT; + c_include_schema_regex TEXT; + c_set_name TEXT; +BEGIN + +IF NOT EXISTS (SELECT 1 FROM pgl_ddl_deploy.set_configs WHERE id = p_set_config_id) THEN + RETURN FALSE; +END IF; + +--This check only applicable to non-include_only_repset_tables and sets using CREATE TABLE events +--We re-assign set_config_id because we want to know if no records are found, leading to NULL +SELECT id, include_schema_regex, set_name +INTO c_set_config_id, c_include_schema_regex, c_set_name +FROM pgl_ddl_deploy.set_configs +WHERE id = p_set_config_id + AND NOT include_only_repset_tables + AND create_tags && '{"CREATE TABLE"}'::TEXT[]; + +RETURN pgl_ddl_deploy.deployment_check_count(c_set_config_id, c_set_name, c_include_schema_regex); + +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deploy(p_set_config_id int) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_deployable BOOLEAN; + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.deployment_check(p_set_config_id) INTO v_deployable; + IF v_deployable THEN + SELECT pgl_ddl_deploy.schema_execute(p_set_config_id, 'deploy_sql') INTO v_result; + RETURN v_result; + ELSE + RETURN v_deployable; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.enable(p_set_config_id int) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_deployable BOOLEAN; + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.deployment_check(p_set_config_id) INTO v_deployable; + IF v_deployable THEN + SELECT pgl_ddl_deploy.schema_execute(p_set_config_id, 'enable_sql') INTO v_result; + RETURN v_result; + ELSE + RETURN v_deployable; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.disable(p_set_config_id int) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_result BOOLEAN; +BEGIN + SELECT pgl_ddl_deploy.schema_execute(p_set_config_id, 'disable_sql') INTO v_result; + RETURN v_result; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.schema_execute(p_set_name text, p_field_name text) RETURNS BOOLEAN AS +$BODY$ +/**** +This function will deploy SQL for all set_configs with given set_name, since this is now allowed. +The version of this function with (int, text) uses a single set_config_id to deploy + */ +DECLARE + v_rec RECORD; + v_in_sql TEXT; + v_out_sql TEXT; +BEGIN + FOR v_rec IN + SELECT id + FROM pgl_ddl_deploy.set_configs + WHERE set_name = p_set_name + LOOP + v_in_sql = $$(SELECT $$||p_field_name||$$ + FROM pgl_ddl_deploy.event_trigger_schema + WHERE id = $$||v_rec.id||$$ + AND set_name = '$$||p_set_name||$$');$$; + EXECUTE v_in_sql INTO v_out_sql; + IF v_out_sql IS NULL THEN + RAISE WARNING 'Failed execution for id % set %', v_rec.id, p_set_name; + RETURN FALSE; + ELSE + EXECUTE v_out_sql; + END IF; + + END LOOP; + RETURN TRUE; +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.schema_execute(p_set_config_id int, p_field_name text) RETURNS BOOLEAN AS +$BODY$ +DECLARE + v_rec RECORD; + v_in_sql TEXT; + v_out_sql TEXT; +BEGIN + v_in_sql = $$(SELECT $$||p_field_name||$$ + FROM pgl_ddl_deploy.event_trigger_schema + WHERE id = $$||p_set_config_id||$$);$$; + EXECUTE v_in_sql INTO v_out_sql; + IF v_out_sql IS NULL THEN + RAISE WARNING 'Failed execution for id % set %', p_set_config_id, (SELECT set_name FROM pgl_ddl_deploy.set_configs WHERE id = p_set_config_id); + RETURN FALSE; + ELSE + EXECUTE v_out_sql; + RETURN TRUE; + END IF; +END; +$BODY$ +LANGUAGE plpgsql; + + +--Just do this to avoid unneeded complexity with dependency_update +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.undeploy(p_set_config_id int) RETURNS BOOLEAN AS +$BODY$ +BEGIN + RETURN pgl_ddl_deploy.schema_execute(p_set_config_id, 'undeploy_sql'); +END; +$BODY$ +LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.undeploy(p_set_name text) RETURNS BOOLEAN AS +$BODY$ +BEGIN + RETURN pgl_ddl_deploy.schema_execute(p_set_name, 'undeploy_sql'); +END; +$BODY$ +LANGUAGE plpgsql; + + +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN exclude_alter_table_subcommands TEXT[]; + +ALTER TABLE pgl_ddl_deploy.set_configs DROP CONSTRAINT repset_tables_only_alter_table; + +SELECT pg_catalog.pg_extension_config_dump('pgl_ddl_deploy.set_configs_id_seq', ''); + +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN ddl_only_replication BOOLEAN NOT NULL DEFAULT FALSE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rep_set_table_wrapper() + RETURNS TABLE (set_id OID, set_reloid REGCLASS) + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +/***** +This handles the rename of pglogical.replication_set_relation to pglogical.replication_set_table from version 1 to 2 + */ +BEGIN + +IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_table') THEN + RETURN QUERY + SELECT r.set_id, r.set_reloid + FROM pglogical.replication_set_table r; + +ELSEIF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_relation') THEN + RETURN QUERY + SELECT r.set_id, r.set_reloid + FROM pglogical.replication_set_relation r; + +ELSE + RAISE EXCEPTION 'No table pglogical.replication_set_relation or pglogical.replication_set_table found'; +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check_wrapper(p_set_config_id integer, p_set_name text) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +DECLARE + v_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_set_config_id INT; + c_include_schema_regex TEXT; + v_include_only_repset_tables BOOLEAN; + v_ddl_only_replication BOOLEAN; + c_set_name TEXT; +BEGIN + +IF p_set_config_id IS NOT NULL AND p_set_name IS NOT NULL THEN + RAISE EXCEPTION 'This function can only be called with one of the two arguments set.'; +END IF; + +IF NOT EXISTS (SELECT 1 FROM pgl_ddl_deploy.set_configs WHERE ((p_set_name is null and id = p_set_config_id) OR (p_set_config_id is null and set_name = p_set_name))) THEN + RETURN FALSE; +END IF; + +/*** + This check is only applicable to NON-include_only_repset_tables and sets using CREATE TABLE events. + It is also bypassed if ddl_only_replication is true in which we never auto-add tables to replication. + We re-assign set_config_id because we want to know if no records are found, leading to NULL +*/ +SELECT id, include_schema_regex, set_name, include_only_repset_tables, ddl_only_replication +INTO c_set_config_id, c_include_schema_regex, c_set_name, v_include_only_repset_tables, v_ddl_only_replication +FROM pgl_ddl_deploy.set_configs +WHERE ((p_set_name is null and id = p_set_config_id) + OR (p_set_config_id is null and set_name = p_set_name)) + AND create_tags && '{"CREATE TABLE"}'::TEXT[]; + +IF v_include_only_repset_tables OR v_ddl_only_replication THEN + RETURN TRUE; +END IF; + +RETURN pgl_ddl_deploy.deployment_check_count(c_set_config_id, c_set_name, c_include_schema_regex); + +END; +$function$; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check(p_set_config_id integer) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +BEGIN + +RETURN pgl_ddl_deploy.deployment_check_wrapper(p_set_config_id, NULL); + +END; +$function$; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check(p_set_name text) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +BEGIN + +RETURN pgl_ddl_deploy.deployment_check_wrapper(NULL, p_set_name); + +END; +$function$; + + + + +CREATE FUNCTION pgl_ddl_deploy.get_altertable_subcmdinfo(pg_ddl_command) + RETURNS text[] IMMUTABLE STRICT + AS '$libdir/ddl_deparse', 'get_altertable_subcmdinfo' LANGUAGE C; + +CREATE FUNCTION pgl_ddl_deploy.get_command_tag(pg_ddl_command) + RETURNS text IMMUTABLE STRICT + AS '$libdir/ddl_deparse', 'get_command_tag' LANGUAGE C; + +CREATE FUNCTION pgl_ddl_deploy.get_command_type(pg_ddl_command) + RETURNS text IMMUTABLE STRICT + AS '$libdir/ddl_deparse', 'get_command_type' LANGUAGE C; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.standard_repset_only_tags() + RETURNS text[] + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT '{ + "ALTER TABLE" + ,COMMENT}'::TEXT[]; +$function$ +; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.standard_create_tags() + RETURNS text[] + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT '{ + "ALTER TABLE" + ,"CREATE SEQUENCE" + ,"ALTER SEQUENCE" + ,"CREATE SCHEMA" + ,"CREATE TABLE" + ,"CREATE FUNCTION" + ,"ALTER FUNCTION" + ,"CREATE TYPE" + ,"ALTER TYPE" + ,"CREATE VIEW" + ,"ALTER VIEW" + ,COMMENT}'::TEXT[]; +$function$ +; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.exclude_regex() + RETURNS text + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT '^(pg_catalog|information_schema|pg_temp.*|pg_toast.*|pgl_ddl_deploy|pglogical|pglogical_ticker|repack)$'::TEXT; +$function$ +; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.common_exclude_alter_table_subcommands() +RETURNS TEXT[] AS +$BODY$ +SELECT ARRAY[ + 'ADD CONSTRAINT', + 'ADD CONSTRAINT (and recurse)', + '(re) ADD CONSTRAINT', + 'ALTER CONSTRAINT', + 'VALIDATE CONSTRAINT', + 'VALIDATE CONSTRAINT (and recurse)', + 'ADD (processed) CONSTRAINT', + 'ADD CONSTRAINT (using index)', + 'DROP CONSTRAINT', + 'DROP CONSTRAINT (and recurse)', + 'SET LOGGED', + 'SET UNLOGGED', + 'SET TABLESPACE', + 'SET RELOPTIONS', + 'RESET RELOPTIONS', + 'REPLACE RELOPTIONS', + 'ENABLE TRIGGER', + 'ENABLE TRIGGER (always)', + 'ENABLE TRIGGER (replica)', + 'DISABLE TRIGGER', + 'ENABLE TRIGGER (all)', + 'DISABLE TRIGGER (all)', + 'ENABLE TRIGGER (user)', + 'DISABLE TRIGGER (user)', + 'ENABLE RULE', + 'ENABLE RULE (always)', + 'ENABLE RULE (replica)', + 'DISABLE RULE', + 'SET OPTIONS']::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.unique_tags() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN + IF NOT NEW.ddl_only_replication AND EXISTS ( + SELECT 1 + FROM pgl_ddl_deploy.set_configs + WHERE id <> NEW.id + AND set_name = NEW.set_name + AND NOT NEW.ddl_only_replication + AND (create_tags && NEW.create_tags + OR drop_tags && NEW.drop_tags)) THEN + RAISE EXCEPTION $$Another set_config already exists for '%' with overlapping create_tags or drop_tags. + Command tags must only appear once per set_name even if using multiple set_configs, unless you + are using the ddl_only_replication setting. + $$, NEW.set_name; + END IF; + RETURN NEW; +END; +$function$ +; + + +ALTER TABLE pgl_ddl_deploy.set_configs ADD CONSTRAINT repset_tables_restricted_tags CHECK ((NOT include_only_repset_tables) OR (include_only_repset_tables AND pgl_ddl_deploy.standard_repset_only_tags() @> create_tags AND drop_tags IS NULL)); + + + +/* pgl_ddl_deploy--1.4--1.5.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +ALTER TABLE pgl_ddl_deploy.set_configs + ADD COLUMN include_everything + BOOLEAN NOT NULL DEFAULT FALSE; + +-- Now we have 3 configuration types +ALTER TABLE pgl_ddl_deploy.set_configs + DROP CONSTRAINT repset_tables_or_regex_inclusion; + +-- Only allow one of them to be chosen +ALTER TABLE pgl_ddl_deploy.set_configs + ADD CONSTRAINT single_configuration_type + CHECK + ((include_schema_regex IS NOT NULL + AND NOT include_only_repset_tables) + OR + (include_only_repset_tables + AND include_schema_regex IS NULL) + OR + (include_everything + AND NOT include_only_repset_tables + AND include_schema_regex IS NULL)); + +ALTER TABLE pgl_ddl_deploy.set_configs + ADD CONSTRAINT ddl_only_restrictions + CHECK (NOT (ddl_only_replication AND include_only_repset_tables)); + +-- Need to adjust to after trigger and change function def +DROP TRIGGER unique_tags ON pgl_ddl_deploy.set_configs; +DROP FUNCTION pgl_ddl_deploy.unique_tags(); + + +-- Support canceling or terminating blocking processes on subscriber +CREATE TYPE pgl_ddl_deploy.signals AS ENUM ('cancel','terminate','cancel_then_terminate'); +ALTER TABLE pgl_ddl_deploy.set_configs + ADD COLUMN signal_blocking_subscriber_sessions pgl_ddl_deploy.signals; +ALTER TABLE pgl_ddl_deploy.set_configs + ADD COLUMN subscriber_lock_timeout INT; + +ALTER TABLE pgl_ddl_deploy.set_configs + ADD CONSTRAINT valid_signal_blocker_config + CHECK + (NOT (lock_safe_deployment AND (signal_blocking_subscriber_sessions IS NOT NULL OR subscriber_lock_timeout IS NOT NULL)) + AND NOT (subscriber_lock_timeout IS NOT NULL AND signal_blocking_subscriber_sessions IS NULL)); + +CREATE TABLE pgl_ddl_deploy.killed_blockers +( + id SERIAL PRIMARY KEY, + signal TEXT, + successful BOOLEAN, + pid INT, + executed_at TIMESTAMPTZ, + usename NAME, + client_addr INET, + xact_start TIMESTAMPTZ, + state_change TIMESTAMPTZ, + state TEXT, + query TEXT, + reported BOOLEAN DEFAULT FALSE, + reported_at TIMESTAMPTZ +); + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.unique_tags() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +DECLARE + v_output TEXT; +BEGIN + WITH dupes AS ( + SELECT set_name, + CASE + WHEN include_only_repset_tables THEN 'include_only_repset_tables' + WHEN include_everything AND NOT ddl_only_replication THEN 'include_everything' + WHEN include_schema_regex IS NOT NULL AND NOT ddl_only_replication THEN 'include_schema_regex' + WHEN ddl_only_replication THEN + CASE + WHEN include_everything THEN 'ddl_only_include_everything' + WHEN include_schema_regex IS NOT NULL THEN 'ddl_only_include_schema_regex' + END + END AS category, + unnest(array_cat(create_tags, drop_tags)) AS command_tag + FROM pgl_ddl_deploy.set_configs + GROUP BY 1, 2, 3 + HAVING COUNT(1) > 1) + + , aggregate_dupe_tags AS ( + SELECT set_name, category, string_agg(command_tag, ', ' ORDER BY command_tag) AS command_tags + FROM dupes + GROUP BY 1, 2 + ) + + SELECT string_agg(format('%s: %s: %s', set_name, category, command_tags), ', ') AS output + INTO v_output + FROM aggregate_dupe_tags; + + IF v_output IS NOT NULL THEN + RAISE EXCEPTION '%', format('You have overlapping configuration types and command tags which is not permitted: %s', v_output); + END IF; + RETURN NULL; +END; +$function$ +; + + +CREATE TRIGGER unique_tags +AFTER INSERT OR UPDATE ON pgl_ddl_deploy.set_configs +FOR EACH ROW EXECUTE PROCEDURE pgl_ddl_deploy.unique_tags(); + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.kill_blockers +(p_signal pgl_ddl_deploy.signals, +p_nspname NAME, +p_relname NAME) +RETURNS TABLE ( +signal pgl_ddl_deploy.signals, +successful BOOLEAN, +raised_message BOOLEAN, +pid INT, +executed_at TIMESTAMPTZ, +usename NAME, +client_addr INET, +xact_start TIMESTAMPTZ, +state_change TIMESTAMPTZ, +state TEXT, +query TEXT, +reported BOOLEAN +) +AS +$BODY$ +/**** +This function is only called on the subscriber on which we are applying DDL, +when it is blocked and hits the configured lock_timeout. + +It is called by the function pgl_ddl_deploy.subscriber_command() only if it hits +lock_timeout and it is configured to send a signal to blocking queries. + +It has three main features: + 1. Signal blocking sessions with either cancel or terminate. + 2. Raise a WARNING message to server logs in case of a kill attempt + 3. Return the recordset with details of killed queries for auditing purposes. +****/ +BEGIN + +RETURN QUERY +SELECT p_signal AS signal, + CASE + WHEN p_signal IS NULL + THEN FALSE + WHEN p_signal = 'cancel' + THEN pg_cancel_backend(l.pid) + WHEN p_signal = 'terminate' + THEN pg_terminate_backend(l.pid) + END AS successful, + CASE + WHEN p_signal IS NULL + THEN FALSE + WHEN p_signal = 'cancel' + THEN pgl_ddl_deploy.raise_message('WARNING', format('Attempting cancel of blocking pid %s, query: %s', l.pid, a.query)) + WHEN p_signal = 'terminate' + THEN pgl_ddl_deploy.raise_message('WARNING', format('Attempting termination of blocking pid %s, query: %s', l.pid, a.query)) + END AS raised_message, + l.pid, + now() AS executed_at, + a.usename, + a.client_addr, + a.xact_start, + a.state_change, + a.state, + a.query, + FALSE AS reported +FROM pg_locks l +INNER JOIN pg_class c on l.relation = c.oid +INNER JOIN pg_namespace n on c.relnamespace = n.oid +INNER JOIN pg_stat_activity a on l.pid = a.pid +-- We do not exclude either postgres user or pglogical processes, because we even want to cancel autovac blocks. +-- It should not be possible to contend with pglogical write processes (at least as of pglogical 2.2), because +-- these run single-threaded using the same process that is doing the DDL and already holds any lock it needs +-- on the target table. +WHERE NOT a.pid = pg_backend_pid() +-- both nspname and relname will be an empty string, thus a no-op, if for some reason one or the other +-- is not found on the provider side in pg_event_trigger_ddl_commands(). This is a safety mechanism! +AND n.nspname = p_nspname +AND c.relname = p_relname +AND a.datname = current_database() +AND c.relkind = 'r' +AND l.locktype = 'relation' +ORDER BY a.state_change DESC; + +END; +$BODY$ +SECURITY DEFINER +LANGUAGE plpgsql VOLATILE; + +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, NAME, NAME) FROM PUBLIC; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.add_role(p_roleoid oid) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +/****** +Assuming roles doing DDL are not superusers, this function grants needed privileges +to run through the pgl_ddl_deploy DDL deployment. +This needs to be run on BOTH provider and subscriber. +******/ +DECLARE + v_rec RECORD; + v_sql TEXT; +BEGIN + + FOR v_rec IN + SELECT quote_ident(rolname) AS rolname FROM pg_roles WHERE oid = p_roleoid + LOOP + + v_sql:=' + GRANT USAGE ON SCHEMA pglogical TO '||v_rec.rolname||'; + GRANT USAGE ON SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replicate_ddl_command(text, text[]) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replication_set_add_table(name, regclass, boolean, text[], text) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.sql_command_tags(text) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, name, name) TO '||v_rec.rolname||'; + GRANT INSERT, UPDATE, SELECT ON ALL TABLES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT USAGE ON ALL SEQUENCES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT SELECT ON ALL TABLES IN SCHEMA pglogical TO '||v_rec.rolname||';'; + + EXECUTE v_sql; + RETURN true; + END LOOP; +RETURN false; +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.subscriber_command +( + p_provider_name NAME, + p_set_name TEXT[], + p_nspname NAME, + p_relname NAME, + p_ddl_sql_sent TEXT, + p_full_ddl TEXT, + p_pid INT, + p_set_config_id INT, + p_queue_subscriber_failures BOOLEAN, + p_signal_blocking_subscriber_sessions pgl_ddl_deploy.signals, + p_lock_timeout INT, +-- This parameter currently only exists to make testing this function easier + p_run_anywhere BOOLEAN = FALSE +) +RETURNS BOOLEAN +AS $pgl_ddl_deploy_sql$ +/**** +This function is what will actually be executed on the subscriber when attempting to apply DDL +changed. It is sent to subscriber(s) via pglogical.replicate_ddl_command. You can see how it +is called based on the the view pgl_ddl_deploy.event_trigger_schema, which is used to create the +specific event trigger functions that will call this function in different ways depending on +configuration in pgl_ddl_deploy.set_configs. + +This function is also used to make testing easier. The regression suite calls +this function to verify basic functionality. +****/ +DECLARE + v_succeeded BOOLEAN; + v_error_message TEXT; + v_attempt_number INT = 0; + v_signal pgl_ddl_deploy.signals; +BEGIN + +--Only run on subscriber with this replication set, and matching provider node name +IF EXISTS (SELECT 1 + FROM pglogical.subscription s + INNER JOIN pglogical.node n + ON n.node_id = s.sub_origin + AND n.node_name = p_provider_name + WHERE sub_replication_sets && p_set_name) OR p_run_anywhere THEN + + v_error_message = NULL; + /**** + If we have configured to kill blocking subscribers, here we set parameters for that: + 1. Whether to cancel or terminate + 2. What lock_timeout to tolerate + ****/ + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + v_signal = CASE WHEN p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' THEN 'cancel' ELSE p_signal_blocking_subscriber_sessions END; + -- We cannot RESET LOCAL lock_timeout but that should not be necessary because it will end with the transaction + EXECUTE format('SET LOCAL lock_timeout TO %s', p_lock_timeout); + END IF; + + /**** + Loop until one of the following takes place: + 1. Successful DDL execution on first attempt + 2. An unexpected ERROR occurs, which will either RAISE or finish with WARNING based on queue_subscriber_failures configuration + 3. Blocking sessions are killed until we finally get a successful DDL execution + ****/ + WHILE TRUE LOOP + BEGIN + + --Execute DDL + RAISE LOG 'pgl_ddl_deploy attempting execution: %', p_full_ddl; + + --Execute DDL - the reason we use execute here is partly to handle no trailing semicolon + EXECUTE p_full_ddl; + + v_succeeded = TRUE; + EXIT; + + EXCEPTION + WHEN lock_not_available THEN + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + -- Change to terminate if we are using cancel_then_terminate and have not been successful after the first iteration + IF v_attempt_number > 0 AND p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' AND v_signal = 'cancel' THEN + v_signal = 'terminate'; + END IF; + INSERT INTO pgl_ddl_deploy.killed_blockers + (signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported) + SELECT + signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported + FROM pgl_ddl_deploy.kill_blockers( + v_signal, + p_nspname, + p_relname + ); + + -- Continue and retry again but allow a brief pause + v_attempt_number = v_attempt_number + 1; + PERFORM pg_sleep(3); + ELSE + -- If p_signal_blocking_subscriber_sessions is not configured but we hit a lock_timeout, + -- then the replication user or cluster is configured with a global lock_timeout. Raise in this case. + RAISE; + END IF; + WHEN OTHERS THEN + IF p_queue_subscriber_failures THEN + RAISE WARNING 'Subscriber DDL failed with errors (see pgl_ddl_deploy.subscriber_logs): %', SQLERRM; + v_succeeded = FALSE; + v_error_message = SQLERRM; + EXIT; + ELSE + RAISE; + END IF; + END; + END LOOP; + + /**** + Since this function is only executed on the subscriber, this INSERT adds a log + to subscriber_logs on the subscriber after execution. + + Note that if we configured queue_subscriber_failures to TRUE in pgl_ddl_deploy.set_configs, then we are + allowing failed DDL to be caught and logged in this table as succeeded = FALSE for later processing. + ****/ + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (p_set_name, + p_pid, + p_provider_name, + p_set_config_id, + current_role, + pg_backend_pid(), + current_timestamp, + p_ddl_sql_sent, + p_full_ddl, + v_succeeded, + v_error_message); + +END IF; + +RETURN v_succeeded; + +END; +$pgl_ddl_deploy_sql$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.raise_message +(p_log_level TEXT, +p_message TEXT) +RETURNS BOOLEAN +AS $BODY$ +BEGIN + +EXECUTE format($$ +DO $block$ +BEGIN +RAISE %s $pgl_ddl_deploy_msg$%s$pgl_ddl_deploy_msg$; +END$block$; +$$, p_log_level, p_message); +RETURN TRUE; + +END; +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.blacklisted_tags() + RETURNS text[] + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT '{ + INSERT, + UPDATE, + DELETE, + TRUNCATE, + ROLLBACK, + "CREATE EXTENSION", + "ALTER EXTENSION", + "DROP EXTENSION"}'::TEXT[]; +$function$ +; + + + + +-- Ensure added roles have write permissions for new tables added +-- Not so easy to pre-package this with default privileges because +-- we can't assume everyone uses the same role to deploy this extension +SELECT pgl_ddl_deploy.add_role(role_oid) +FROM ( +SELECT DISTINCT r.oid AS role_oid +FROM information_schema.table_privileges tp +INNER JOIN pg_roles r ON r.rolname = tp.grantee AND NOT r.rolsuper +WHERE table_schema = 'pgl_ddl_deploy' + AND privilege_type = 'INSERT' + AND table_name = 'subscriber_logs' +) roles_with_existing_privileges; + + +/* pgl_ddl_deploy--1.5--1.6.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +CREATE FUNCTION pgl_ddl_deploy.current_query() +RETURNS TEXT AS +'MODULE_PATHNAME', 'pgl_ddl_deploy_current_query' +LANGUAGE C VOLATILE STRICT; + +-- Drop UPDATE event for this trigger, which leads to unexpected behavior +DROP TRIGGER set_tag_defaults ON pgl_ddl_deploy.set_configs; +CREATE TRIGGER set_tag_defaults +BEFORE INSERT ON pgl_ddl_deploy.set_configs +FOR EACH ROW EXECUTE PROCEDURE pgl_ddl_deploy.set_tag_defaults(); + + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.kill_blockers +(p_signal pgl_ddl_deploy.signals, +p_nspname NAME, +p_relname NAME) +RETURNS TABLE ( +signal pgl_ddl_deploy.signals, +successful BOOLEAN, +raised_message BOOLEAN, +pid INT, +executed_at TIMESTAMPTZ, +usename NAME, +client_addr INET, +xact_start TIMESTAMPTZ, +state_change TIMESTAMPTZ, +state TEXT, +query TEXT, +reported BOOLEAN +) +AS +$BODY$ +/**** +This function is only called on the subscriber on which we are applying DDL, +when it is blocked and hits the configured lock_timeout. + +It is called by the function pgl_ddl_deploy.subscriber_command() only if it hits +lock_timeout and it is configured to send a signal to blocking queries. + +It has three main features: + 1. Signal blocking sessions with either cancel or terminate. + 2. Raise a WARNING message to server logs in case of a kill attempt + 3. Return the recordset with details of killed queries for auditing purposes. +****/ +BEGIN + +RETURN QUERY +SELECT DISTINCT ON (l.pid) + p_signal AS signal, + CASE + WHEN p_signal IS NULL + THEN FALSE + WHEN p_signal = 'cancel' + THEN pg_cancel_backend(l.pid) + WHEN p_signal = 'terminate' + THEN pg_terminate_backend(l.pid) + END AS successful, + CASE + WHEN p_signal IS NULL + THEN FALSE + WHEN p_signal = 'cancel' + THEN pgl_ddl_deploy.raise_message('WARNING', format('Attempting cancel of blocking pid %s, query: %s', l.pid, a.query)) + WHEN p_signal = 'terminate' + THEN pgl_ddl_deploy.raise_message('WARNING', format('Attempting termination of blocking pid %s, query: %s', l.pid, a.query)) + END AS raised_message, + l.pid, + now() AS executed_at, + a.usename, + a.client_addr, + a.xact_start, + a.state_change, + a.state, + a.query, + FALSE AS reported +FROM pg_locks l +INNER JOIN pg_class c on l.relation = c.oid +INNER JOIN pg_namespace n on c.relnamespace = n.oid +INNER JOIN pg_stat_activity a on l.pid = a.pid +/*** + We need to check if this is an inheritance parent, + because even a share lock on a child will prevent DDL on parent +***/ +LEFT JOIN pg_inherits pi ON pi.inhrelid = c.oid +LEFT JOIN pg_class ipc on ipc.oid = pi.inhparent +LEFT JOIN pg_namespace ipn on ipn.oid = ipc.relnamespace +-- We do not exclude either postgres user or pglogical processes, because we even want to cancel autovac blocks. +-- It should not be possible to contend with pglogical write processes (at least as of pglogical 2.2), because +-- these run single-threaded using the same process that is doing the DDL and already holds any lock it needs +-- on the target table. +WHERE NOT a.pid = pg_backend_pid() +-- both nspname and relname will be an empty string, thus a no-op, if for some reason one or the other +-- is not found on the provider side in pg_event_trigger_ddl_commands(). This is a safety mechanism! +AND ((n.nspname = p_nspname AND c.relname = p_relname) +OR (ipn.nspname = p_nspname AND ipc.relname = p_relname)) +AND a.datname = current_database() +AND c.relkind = 'r' +AND l.locktype = 'relation' +ORDER BY l.pid, a.state_change DESC; + +END; +$BODY$ +SECURITY DEFINER +LANGUAGE plpgsql VOLATILE; + +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, NAME, NAME) FROM PUBLIC; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.raise_message +(p_log_level TEXT, +p_message TEXT) +RETURNS BOOLEAN +AS $BODY$ +BEGIN + +EXECUTE format($$ +DO $block$ +BEGIN +RAISE %s $pgl_ddl_deploy_msg$%s$pgl_ddl_deploy_msg$; +END$block$; +$$, p_log_level, REPLACE(p_message,'%','%%')); +RETURN TRUE; + +END; +$BODY$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.standard_create_tags() + RETURNS text[] + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT '{ + "ALTER TABLE" + ,"CREATE SEQUENCE" + ,"ALTER SEQUENCE" + ,"CREATE SCHEMA" + ,"CREATE TABLE" + ,"CREATE FUNCTION" + ,"ALTER FUNCTION" + ,"CREATE TYPE" + ,"ALTER TYPE" + ,"CREATE VIEW" + ,"ALTER VIEW" + ,COMMENT + ,"CREATE RULE" + ,"CREATE TRIGGER" + ,"ALTER TRIGGER"}'::TEXT[]; +$function$ +; + + + + +/* pgl_ddl_deploy--1.6--1.7.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.add_role(p_roleoid oid) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +/****** +Assuming roles doing DDL are not superusers, this function grants needed privileges +to run through the pgl_ddl_deploy DDL deployment. +This needs to be run on BOTH provider and subscriber. +******/ +DECLARE + v_rec RECORD; + v_sql TEXT; + v_rsat_args TEXT; +BEGIN + + FOR v_rec IN + SELECT quote_ident(rolname) AS rolname FROM pg_roles WHERE oid = p_roleoid + LOOP + + v_rsat_args:=pg_get_function_identity_arguments('pglogical.replication_set_add_table'::REGPROC); + + + v_sql:=' + GRANT USAGE ON SCHEMA pglogical TO '||v_rec.rolname||'; + GRANT USAGE ON SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replicate_ddl_command(text, text[]) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replication_set_add_table(' || v_rsat_args || ') TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.sql_command_tags(text) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, name, name) TO '||v_rec.rolname||'; + GRANT INSERT, UPDATE, SELECT ON ALL TABLES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT USAGE ON ALL SEQUENCES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT SELECT ON ALL TABLES IN SCHEMA pglogical TO '||v_rec.rolname||';'; + + + + + EXECUTE v_sql; + RETURN true; + END LOOP; +RETURN false; +END; +$function$ +; + + +/* pgl_ddl_deploy--1.7--2.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +/* + * We need to re-deploy the trigger function definitions + * which will have changed with this extension update. So + * here we undeploy them, and save which ones we need to + * recreate later. +*/ +DO $$ +BEGIN + +IF EXISTS (SELECT 1 FROM pg_views WHERE schemaname = 'pgl_ddl_deploy' AND viewname = 'event_trigger_schema') THEN + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +CREATE TEMP TABLE ddl_deploy_to_refresh AS +SELECT id, pgl_ddl_deploy.undeploy(id) AS undeployed +FROM pgl_ddl_deploy.event_trigger_schema +WHERE is_deployed; + +ELSE + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +CREATE TEMP TABLE ddl_deploy_to_refresh AS +SELECT NULL::INT AS id; + +END IF; +END$$; + +CREATE TYPE pgl_ddl_deploy.driver AS ENUM ('pglogical', 'native'); +-- Not possible that any existing config would be native, so: +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN driver pgl_ddl_deploy.driver NOT NULL DEFAULT 'pglogical'; +DROP FUNCTION IF EXISTS pgl_ddl_deploy.rep_set_table_wrapper(); +DROP FUNCTION IF EXISTS pgl_ddl_deploy.deployment_check_count(integer, text, text); +DROP FUNCTION pgl_ddl_deploy.subscriber_command +( + p_provider_name NAME, + p_set_name TEXT[], + p_nspname NAME, + p_relname NAME, + p_ddl_sql_sent TEXT, + p_full_ddl TEXT, + p_pid INT, + p_set_config_id INT, + p_queue_subscriber_failures BOOLEAN, + p_signal_blocking_subscriber_sessions pgl_ddl_deploy.signals, + p_lock_timeout INT, +-- This parameter currently only exists to make testing this function easier + p_run_anywhere BOOLEAN +); + +CREATE TABLE pgl_ddl_deploy.queue( +queued_at timestamp with time zone not null, +role name not null, +pubnames text[], +message_type "char" not null, +message text not null +); +COMMENT ON TABLE pgl_ddl_deploy.queue IS 'Modeled on the pglogical.queue table for native logical replication ddl'; +ALTER TABLE pgl_ddl_deploy.queue REPLICA IDENTITY FULL; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.override() RETURNS BOOLEAN AS $BODY$ +BEGIN +RETURN FALSE; +END; +$BODY$ +LANGUAGE plpgsql IMMUTABLE; + +-- NOTE - this duplicates execute_queued_ddl.sql function file but is executed here for the upgrade/build path +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.execute_queued_ddl() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN + +/*** +Native logical replication does not support row filtering, so as a result, +we need to do processing downstream to ensure we only process rows we care about. + +For example, if we propagate some DDL to system 1 and some other to system 2, +all rows will still come through this trigger. We filter out rows based on +matching pubnames with pg_subscription.subpublications + +If a row arrives here (the subscriber), it must mean that it was propagated +***/ + +IF NEW.message_type = pgl_ddl_deploy.queue_ddl_message_type() AND + (pgl_ddl_deploy.override() OR ((SELECT COUNT(1) FROM pg_subscription s + WHERE subpublications && NEW.pubnames) > 0)) THEN + + -- See https://www.postgresql.org/message-id/CAMa1XUh7ZVnBzORqjJKYOv4_pDSDUCvELRbkF0VtW7pvDW9rZw@mail.gmail.com + IF NEW.message ~* 'pgl_ddl_deploy.notify_subscription_refresh' THEN + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (NEW.pubnames[1], + NULL, + NULL, + NULL, + current_role, + pg_backend_pid(), + current_timestamp, + NEW.message, + NEW.message, + FALSE, + 'Unsupported automated ALTER SUBSCRIPTION ... REFRESH PUBLICATION until bugfix'); + ELSE + EXECUTE 'SET ROLE '||quote_ident(NEW.role)||';'; + EXECUTE NEW.message::TEXT; + END IF; + + RETURN NEW; +ELSE + RETURN NULL; +END IF; + +END; +$function$ +; + +CREATE TRIGGER execute_queued_ddl +BEFORE INSERT ON pgl_ddl_deploy.queue +FOR EACH ROW EXECUTE PROCEDURE pgl_ddl_deploy.execute_queued_ddl(); + +-- This must only fire on the replica +ALTER TABLE pgl_ddl_deploy.queue ENABLE REPLICA TRIGGER execute_queued_ddl; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.replicate_ddl_command(command text, pubnames text[]) + RETURNS BOOLEAN + LANGUAGE plpgsql +AS $function$ +-- Modeled after pglogical's replicate_ddl_command but in support of native logical replication +BEGIN + +-- NOTE: pglogical uses clock_timestamp() to log queued_at times and we do the same here +INSERT INTO pgl_ddl_deploy.queue (queued_at, role, pubnames, message_type, message) +VALUES (clock_timestamp(), current_role, pubnames, pgl_ddl_deploy.queue_ddl_message_type(), command); + +RETURN TRUE; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.add_table_to_replication(p_driver pgl_ddl_deploy.driver, p_set_name name, p_relation regclass, p_synchronize_data boolean DEFAULT false) + RETURNS BOOLEAN + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +DECLARE + v_schema NAME; + v_table NAME; + v_result BOOLEAN = false; +BEGIN +IF p_driver = 'pglogical' THEN + + SELECT pglogical.replication_set_add_table( + set_name:=p_set_name + ,relation:=p_relation + ,synchronize_data:=p_synchronize_data + ) INTO v_result; + +ELSEIF p_driver = 'native' THEN + + SELECT nspname, relname INTO v_schema, v_table + FROM pg_class c + JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.oid = p_relation::OID; + + EXECUTE 'ALTER PUBLICATION '||quote_ident(p_set_name)||' ADD TABLE '||quote_ident(v_schema)||'.'||quote_ident(v_table)||';'; + + -- We use true to synchronize data here, not taking the value from p_synchronize_data. This is because of the different way + -- that native logical works, and that changes are not queued from the time of the table being added to replication. Thus, we + -- by default WILL use COPY_DATA = true + + -- This needs to be in a DO block currently because of how the DDL is processed on the subscriber. + PERFORM pgl_ddl_deploy.replicate_ddl_command($$DO $AUTO_REPLICATE_BLOCK$ + BEGIN + PERFORM pgl_ddl_deploy.notify_subscription_refresh('$$||p_set_name||$$', true); + END$AUTO_REPLICATE_BLOCK$;$$, array[p_set_name]); + v_result = true; + +ELSE + +RAISE EXCEPTION 'Unsupported driver specified'; + +END IF; + +RETURN v_result; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.notify_subscription_refresh(p_set_name name, p_copy_data boolean DEFAULT TRUE) + RETURNS BOOLEAN + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +DECLARE + v_rec RECORD; + v_sql TEXT; +BEGIN + + IF NOT EXISTS (SELECT 1 FROM pg_subscription WHERE subpublications && array[p_set_name::text]) THEN + RAISE EXCEPTION 'No subscription to publication % exists', p_set_name; + END IF; + + FOR v_rec IN + SELECT unnest(subpublications) AS pubname, subname + FROM pg_subscription + WHERE subpublications && array[p_set_name::text] + LOOP + + v_sql = $$ALTER SUBSCRIPTION $$||quote_ident(v_rec.subname)||$$ REFRESH PUBLICATION WITH ( COPY_DATA = '$$||p_copy_data||$$');$$; + RAISE LOG 'pgl_ddl_deploy executing: %', v_sql; + EXECUTE v_sql; + + END LOOP; + +RETURN TRUE; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rep_set_table_wrapper() + RETURNS TABLE (id OID, relid REGCLASS, name NAME, driver pgl_ddl_deploy.driver) + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +/***** +This handles the rename of pglogical.replication_set_relation to pglogical.replication_set_table from version 1 to 2 + */ +BEGIN + +IF current_setting('server_version_num')::INT < 100000 THEN + IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_table') THEN + RETURN QUERY + SELECT r.set_id AS id, r.set_reloid AS relid, rs.set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set_table r + JOIN pglogical.replication_set rs USING (set_id); + + ELSEIF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_relation') THEN + RETURN QUERY + SELECT r.set_id AS id, r.set_reloid AS relid, rs.set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set_relation r + JOIN pglogical.replication_set rs USING (set_id); + + ELSE + RAISE EXCEPTION 'No table pglogical.replication_set_relation or pglogical.replication_set_table found'; + END IF; + +ELSE + IF NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pglogical') THEN + RETURN QUERY + SELECT p.oid AS id, prrelid::REGCLASS AS relid, pubname AS name, 'native'::pgl_ddl_deploy.driver AS driver + FROM pg_publication p + JOIN pg_publication_rel ppr ON ppr.prpubid = p.oid; + + ELSEIF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_table') THEN + RETURN QUERY + SELECT r.set_id AS id, r.set_reloid AS relid, rs.set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set_table r + JOIN pglogical.replication_set rs USING (set_id) + UNION ALL + SELECT p.oid AS id, prrelid::REGCLASS AS relid, pubname AS name, 'native'::pgl_ddl_deploy.driver AS driver + FROM pg_publication p + JOIN pg_publication_rel ppr ON ppr.prpubid = p.oid; + + ELSEIF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical' AND tablename = 'replication_set_relation') THEN + RETURN QUERY + SELECT r.set_id AS id, r.set_reloid AS relid, rs.set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set_relation r + JOIN pglogical.replication_set rs USING (set_id) + UNION ALL + SELECT p.oid AS id, prrelid::REGCLASS AS relid, pubname AS name, 'native'::pgl_ddl_deploy.driver AS driver + FROM pg_publication p + JOIN pg_publication_rel ppr ON ppr.prpubid = p.oid; + END IF; +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rep_set_wrapper() + RETURNS TABLE (id OID, name NAME, driver pgl_ddl_deploy.driver) + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +/***** +This handles the rename of pglogical.replication_set_relation to pglogical.replication_set_table from version 1 to 2 + */ +BEGIN + +IF current_setting('server_version_num')::INT < 100000 THEN + IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical') THEN + RETURN QUERY + SELECT set_id AS id, set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set rs; + + ELSE + RAISE EXCEPTION 'pglogical required for version prior to Postgres 10'; + END IF; + +ELSE + IF NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pglogical') THEN + RETURN QUERY + SELECT p.oid AS id, pubname AS name, 'native'::pgl_ddl_deploy.driver AS driver + FROM pg_publication p; + + ELSEIF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'pglogical') THEN + RETURN QUERY + SELECT set_id AS id, set_name AS name, 'pglogical'::pgl_ddl_deploy.driver AS driver + FROM pglogical.replication_set rs + UNION ALL + SELECT p.oid AS id, pubname AS name, 'native'::pgl_ddl_deploy.driver AS driver + FROM pg_publication p; + ELSE + RAISE EXCEPTION 'Unexpected exception'; + END IF; + + +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check_count(p_set_config_id integer, p_set_name text, p_include_schema_regex text, p_driver pgl_ddl_deploy.driver) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +DECLARE + v_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); +BEGIN + +--If the check is not applicable, pass it +IF p_set_config_id IS NULL THEN + RETURN TRUE; +END IF; + +SELECT COUNT(1) +INTO v_count +FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* p_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = p_set_name + AND rsr.relid = c.oid + AND rsr.driver = p_driver); + +IF v_count > 0 THEN + RAISE WARNING $ERR$ + Deployment of auto-replication for id % set_name % failed + because % tables are already queued to be added to replication + based on your configuration. These tables need to be added to + replication manually and synced, otherwise change your configuration. + Debug query: %$ERR$, + p_set_config_id, + p_set_name, + v_count, + $SQL$ + SELECT n.nspname, c.relname + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* '$SQL$||p_include_schema_regex||$SQL$' + AND n.nspname !~* '$SQL$||c_exclude_always||$SQL$' + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = '$SQL$||p_set_name||$SQL$' + AND rsr.relid = c.oid + AND rsr.driver = (SELECT driver FROM pgl_ddl_deploy.set_configs WHERE set_name = '$SQL$||p_set_name||$SQL$')); + $SQL$; + RETURN FALSE; +END IF; + +RETURN TRUE; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.deployment_check_wrapper(p_set_config_id integer, p_set_name text) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +DECLARE + v_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_set_config_id INT; + c_include_schema_regex TEXT; + v_include_only_repset_tables BOOLEAN; + v_ddl_only_replication BOOLEAN; + c_set_name TEXT; + v_driver pgl_ddl_deploy.driver; +BEGIN + +IF p_set_config_id IS NOT NULL AND p_set_name IS NOT NULL THEN + RAISE EXCEPTION 'This function can only be called with one of the two arguments set.'; +END IF; + +IF NOT EXISTS (SELECT 1 FROM pgl_ddl_deploy.set_configs WHERE ((p_set_name is null and id = p_set_config_id) OR (p_set_config_id is null and set_name = p_set_name))) THEN + RETURN FALSE; +END IF; + +/*** + This check is only applicable to NON-include_only_repset_tables and sets using CREATE TABLE events. + It is also bypassed if ddl_only_replication is true in which we never auto-add tables to replication. + We re-assign set_config_id because we want to know if no records are found, leading to NULL +*/ +SELECT id, include_schema_regex, set_name, include_only_repset_tables, ddl_only_replication, driver +INTO c_set_config_id, c_include_schema_regex, c_set_name, v_include_only_repset_tables, v_ddl_only_replication, v_driver +FROM pgl_ddl_deploy.set_configs +WHERE ((p_set_name is null and id = p_set_config_id) + OR (p_set_config_id is null and set_name = p_set_name)) + AND create_tags && '{"CREATE TABLE"}'::TEXT[]; + +IF v_include_only_repset_tables OR v_ddl_only_replication THEN + RETURN TRUE; +END IF; + +RETURN pgl_ddl_deploy.deployment_check_count(c_set_config_id, c_set_name, c_include_schema_regex, v_driver); + +END; +$function$; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.is_subscriber(p_driver pgl_ddl_deploy.driver, p_name TEXT[], p_provider_name NAME = NULL) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +BEGIN + +IF p_driver = 'pglogical' THEN + + RETURN EXISTS (SELECT 1 + FROM pglogical.subscription s + INNER JOIN pglogical.node n + ON n.node_id = s.sub_origin + AND n.node_name = p_provider_name + WHERE sub_replication_sets && p_name); + +ELSEIF p_driver = 'native' THEN + + RETURN EXISTS (SELECT 1 + FROM pg_subscription s + WHERE subpublications && p_name); + +ELSE + +RAISE EXCEPTION 'Unsupported driver specified'; + +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.subscriber_command +( + p_provider_name NAME, + p_set_name TEXT[], + p_nspname NAME, + p_relname NAME, + p_ddl_sql_sent TEXT, + p_full_ddl TEXT, + p_pid INT, + p_set_config_id INT, + p_queue_subscriber_failures BOOLEAN, + p_signal_blocking_subscriber_sessions pgl_ddl_deploy.signals, + p_lock_timeout INT, + p_driver pgl_ddl_deploy.driver, +-- This parameter currently only exists to make testing this function easier + p_run_anywhere BOOLEAN = FALSE +) +RETURNS BOOLEAN +AS $pgl_ddl_deploy_sql$ +/**** +This function is what will actually be executed on the subscriber when attempting to apply DDL +changed. It is sent to subscriber(s) via pglogical.replicate_ddl_command. You can see how it +is called based on the the view pgl_ddl_deploy.event_trigger_schema, which is used to create the +specific event trigger functions that will call this function in different ways depending on +configuration in pgl_ddl_deploy.set_configs. + +This function is also used to make testing easier. The regression suite calls +this function to verify basic functionality. +****/ +DECLARE + v_succeeded BOOLEAN; + v_error_message TEXT; + v_attempt_number INT = 0; + v_signal pgl_ddl_deploy.signals; +BEGIN + +IF pgl_ddl_deploy.is_subscriber(p_driver, p_set_name, p_provider_name) OR p_run_anywhere THEN + + v_error_message = NULL; + /**** + If we have configured to kill blocking subscribers, here we set parameters for that: + 1. Whether to cancel or terminate + 2. What lock_timeout to tolerate + ****/ + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + v_signal = CASE WHEN p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' THEN 'cancel' ELSE p_signal_blocking_subscriber_sessions END; + -- We cannot RESET LOCAL lock_timeout but that should not be necessary because it will end with the transaction + EXECUTE format('SET LOCAL lock_timeout TO %s', p_lock_timeout); + END IF; + + /**** + Loop until one of the following takes place: + 1. Successful DDL execution on first attempt + 2. An unexpected ERROR occurs, which will either RAISE or finish with WARNING based on queue_subscriber_failures configuration + 3. Blocking sessions are killed until we finally get a successful DDL execution + ****/ + WHILE TRUE LOOP + BEGIN + + --Execute DDL + RAISE LOG 'pgl_ddl_deploy attempting execution: %', p_full_ddl; + + --Execute DDL - the reason we use execute here is partly to handle no trailing semicolon + EXECUTE p_full_ddl; + + v_succeeded = TRUE; + EXIT; + + EXCEPTION + WHEN lock_not_available THEN + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + -- Change to terminate if we are using cancel_then_terminate and have not been successful after the first iteration + IF v_attempt_number > 0 AND p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' AND v_signal = 'cancel' THEN + v_signal = 'terminate'; + END IF; + INSERT INTO pgl_ddl_deploy.killed_blockers + (signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported) + SELECT + signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported + FROM pgl_ddl_deploy.kill_blockers( + v_signal, + p_nspname, + p_relname + ); + + -- Continue and retry again but allow a brief pause + v_attempt_number = v_attempt_number + 1; + PERFORM pg_sleep(3); + ELSE + -- If p_signal_blocking_subscriber_sessions is not configured but we hit a lock_timeout, + -- then the replication user or cluster is configured with a global lock_timeout. Raise in this case. + RAISE; + END IF; + WHEN OTHERS THEN + IF p_queue_subscriber_failures THEN + RAISE WARNING 'Subscriber DDL failed with errors (see pgl_ddl_deploy.subscriber_logs): %', SQLERRM; + v_succeeded = FALSE; + v_error_message = SQLERRM; + EXIT; + ELSE + RAISE; + END IF; + END; + END LOOP; + + /**** + Since this function is only executed on the subscriber, this INSERT adds a log + to subscriber_logs on the subscriber after execution. + + Note that if we configured queue_subscriber_failures to TRUE in pgl_ddl_deploy.set_configs, then we are + allowing failed DDL to be caught and logged in this table as succeeded = FALSE for later processing. + ****/ + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (p_set_name, + p_pid, + p_provider_name, + p_set_config_id, + current_role, + pg_backend_pid(), + current_timestamp, + p_ddl_sql_sent, + p_full_ddl, + v_succeeded, + v_error_message); + +END IF; + +RETURN v_succeeded; + +END; +$pgl_ddl_deploy_sql$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.queue_ddl_message_type() + RETURNS "char" + LANGUAGE sql + IMMUTABLE +AS $function$ +SELECT 'Q'::"char"; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.provider_node_name(p_driver pgl_ddl_deploy.driver) + RETURNS NAME + LANGUAGE plpgsql +AS $function$ +DECLARE v_node_name NAME; +BEGIN + +IF p_driver = 'pglogical' THEN + + SELECT n.node_name INTO v_node_name + FROM pglogical.node n + INNER JOIN pglogical.local_node ln + USING (node_id); + RETURN v_node_name; + +ELSEIF p_driver = 'native' THEN + + RETURN NULL::NAME; + +ELSE + +RAISE EXCEPTION 'Unsupported driver specified'; + +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE VIEW pgl_ddl_deploy.event_trigger_schema AS +WITH vars AS +(SELECT + sc.id, + set_name, + 'pgl_ddl_deploy.auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_function_name, + 'auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_trigger_name, + 'auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_trigger_name, + 'auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_trigger_name, + include_schema_regex, + include_only_repset_tables, + create_tags, + drop_tags, + ddl_only_replication, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + sc.driver, + + /**** + These constants in DECLARE portion of all functions is identical and can be shared + */ + $BUILD$ + c_search_path TEXT = (SELECT current_setting('search_path')); + c_provider_name TEXT; + --TODO: How do I decide which replication set we care about? + v_pid INT = pg_backend_pid(); + v_rec RECORD; + v_ddl_sql_raw TEXT; + v_ddl_sql_sent TEXT; + v_full_ddl TEXT; + v_sql_tags TEXT[]; + v_cmd_rec RECORD; + v_subcmd_rec RECORD; + v_excluded_subcommands TEXT; + v_contains_any_valid_subcommand INT; + + /***** + We need to strip the DDL of: + 1. Transaction begin and commit, which cannot run inside plpgsql + *****/ + v_ddl_strip_regex TEXT = '(begin\W*transaction\W*|begin\W*work\W*|begin\W*|commit\W*transaction\W*|commit\W*work\W*|commit\W*);'; + v_txid BIGINT; + v_ddl_length INT; + v_sql TEXT; + v_cmd_count INT; + v_match_count INT; + v_exclude_always_match_count INT; + v_nspname TEXT; + v_relname TEXT; + v_error TEXT; + v_error_detail TEXT; + v_context TEXT; + v_excluded_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_exception_msg TEXT = 'Deployment exception logged in pgl_ddl_deploy.exceptions'; + + --Configurable options in function setup + c_set_config_id INT = $BUILD$||sc.id::TEXT||$BUILD$; + -- Even though pglogical supports an array of sets, we only pipe DDL through one at a time + -- So c_set_name is a text not text[] data type. + c_set_name TEXT = '$BUILD$||set_name||$BUILD$'; + c_driver pgl_ddl_deploy.driver = '$BUILD$||sc.driver||$BUILD$'; + c_include_schema_regex TEXT = $BUILD$||COALESCE(''''||include_schema_regex||'''','NULL')||$BUILD$; + c_lock_safe_deployment BOOLEAN = $BUILD$||lock_safe_deployment||$BUILD$; + c_allow_multi_statements BOOLEAN = $BUILD$||allow_multi_statements||$BUILD$; + c_include_only_repset_tables BOOLEAN = $BUILD$||include_only_repset_tables||$BUILD$; + c_include_everything BOOLEAN = $BUILD$||include_everything||$BUILD$; + c_queue_subscriber_failures BOOLEAN = $BUILD$||queue_subscriber_failures||$BUILD$; + c_create_tags TEXT[] = '$BUILD$||create_tags::TEXT||$BUILD$'; + c_blacklisted_tags TEXT[] = '$BUILD$||blacklisted_tags::TEXT||$BUILD$'; + c_exclude_alter_table_subcommands TEXT[] = $BUILD$||COALESCE(quote_literal(exclude_alter_table_subcommands::TEXT),'NULL')||$BUILD$; + c_signal_blocking_subscriber_sessions TEXT = $BUILD$||COALESCE(quote_literal(signal_blocking_subscriber_sessions::TEXT),'NULL')||$BUILD$; + c_subscriber_lock_timeout INT = $BUILD$||COALESCE(subscriber_lock_timeout::TEXT,'NULL')||$BUILD$; + + --Constants based on configuration + c_exec_prefix TEXT =(CASE + WHEN c_lock_safe_deployment + THEN 'SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$' + ELSE '' + END); + c_exec_suffix TEXT = (CASE + WHEN c_lock_safe_deployment + THEN '$PGL_DDL_DEPLOY$);' + ELSE '' + END); + $BUILD$::TEXT AS declare_constants, + + $BUILD$ + --If there are any matches to our replication config, get the query + --This will either be sent, or logged at this point if not deployable + IF (c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0 THEN + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + v_txid = txid_current(); + END IF; + $BUILD$::TEXT AS shared_get_query, +/**** + This is the portion of the event trigger function that evaluates if SQL + is appropriate to propagate, and does propagate the event. It is shared + between the normal and drop event trigger functions. + */ + $BUILD$ + /**** + A multi-statement SQL command may fire this event trigger more than once + This check ensures the SQL is propagated only once, if at all + */ + IF EXISTS + (SELECT 1 FROM pgl_ddl_deploy.events + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + OR EXISTS + (SELECT 1 FROM pgl_ddl_deploy.unhandled + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + THEN + RETURN; + END IF; + + /**** + Get the command tags and reject blacklisted tags + */ + v_sql_tags:=(SELECT pgl_ddl_deploy.sql_command_tags(v_ddl_sql_raw)); + IF (SELECT c_blacklisted_tags && v_sql_tags) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_command_tags', + v_txid); + RETURN; + /**** + If we are not allowing multi-statements at all, reject + */ + ELSEIF (SELECT ARRAY[TG_TAG]::TEXT[] <> v_sql_tags WHERE NOT c_allow_multi_statements) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_multi_statement', + v_txid); + RETURN; + END IF; + + /**** + If this is an ALTER TABLE statement and we are excluding any subcommand tags, process now. + Note the following. + + Because there can be more than one subcommand, we have a limited ability + to filter out subcommands until such a time as we may have a mechanism for rebuilding only + the SQL we want. In other words, if we have one subcommand that we DO want (i.e. ADD COLUMN) + and one we don't want (i.e. REFERENCES) in the same SQL, and we are "excluding" the latter, + we can't do that exclusion safely because we WANT the ADD COLUMN statement. In such a case, + we are still going to allow the DDL to go through because it's better to break replication than + miss a column addition. + + But if the only subcommand is an excluded one, i.e. ADD CONSTRAINT, then we will indeed ignore + the DDL and the function will RETURN without executing replicate_ddl_command. + */ + IF TG_TAG = 'ALTER TABLE' AND c_exclude_alter_table_subcommands IS NOT NULL THEN + FOR v_cmd_rec IN + SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF pgl_ddl_deploy.get_command_type(v_cmd_rec.command) = 'alter table' THEN + WITH subcommands AS ( + SELECT subcommand, + c_exclude_alter_table_subcommands && ARRAY[subcommand] AS subcommand_is_excluded, + MAX(CASE WHEN c_exclude_alter_table_subcommands && ARRAY[subcommand] THEN 0 ELSE 1 END) OVER() AS contains_any_valid_subcommand + FROM unnest(pgl_ddl_deploy.get_altertable_subcmdinfo(v_cmd_rec.command)) AS subcommand + ) + + SELECT (SELECT string_agg(subcommand,', ') FROM subcommands WHERE subcommand_is_excluded), + (SELECT contains_any_valid_subcommand FROM subcommands LIMIT 1) + INTO v_excluded_subcommands, + v_contains_any_valid_subcommand; + IF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 0 THEN + RAISE LOG 'Not processing DDL due to excluded subcommand(s): %: %', v_excluded_subcommands, v_ddl_sql_raw; + RETURN; + ELSEIF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 1 THEN + RAISE WARNING $INNER_BLOCK$Filtering out more than one subcommand in one ALTER TABLE is not supported. + Allowing to proceed: Rejected: %, SQL: %$INNER_BLOCK$, v_excluded_subcommands, v_ddl_sql_raw; + END IF; + END IF; + END LOOP; + END IF; + + v_ddl_sql_sent = v_ddl_sql_raw; + + --If there are BEGIN/COMMIT tags, attempt to strip and reparse + IF (SELECT ARRAY['BEGIN','COMMIT']::TEXT[] && v_sql_tags) THEN + v_ddl_sql_sent = regexp_replace(v_ddl_sql_sent, v_ddl_strip_regex, '', 'ig'); + + --Sanity reparse + PERFORM pgl_ddl_deploy.sql_command_tags(v_ddl_sql_sent); + END IF; + + --Get provider name, in order only to run command on a subscriber to this provider + c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); + + /* + Build replication DDL command which will conditionally run only on the subscriber + In other words, this MUST be a no-op on the provider + **Because the DDL has already run at this point (ddl_command_end)** + */ + v_full_ddl:=$INNER_BLOCK$ + --Be sure to use provider's search_path for SQL environment consistency + SET SEARCH_PATH TO $INNER_BLOCK$|| + CASE WHEN COALESCE(c_search_path,'') IN('','""') THEN quote_literal('') ELSE c_search_path END||$INNER_BLOCK$; + + $INNER_BLOCK$||c_exec_prefix||v_ddl_sql_sent||c_exec_suffix||$INNER_BLOCK$ + ; + $INNER_BLOCK$; + RAISE DEBUG 'v_full_ddl: %', v_full_ddl; + RAISE DEBUG 'c_set_config_id: %', c_set_config_id; + RAISE DEBUG 'c_set_name: %', c_set_name; + RAISE DEBUG 'c_driver: %', c_driver; + RAISE DEBUG 'v_ddl_sql_sent: %', v_ddl_sql_sent; + + v_sql:=$INNER_BLOCK$ + SELECT $BUILD$||CASE + WHEN sc.driver = 'native' + THEN 'pgl_ddl_deploy' + WHEN sc.driver = 'pglogical' + THEN 'pglogical' + ELSE 'ERROR-EXCEPTION' END||$BUILD$.replicate_ddl_command($REPLICATE_DDL_COMMAND$ + SELECT pgl_ddl_deploy.subscriber_command + ( + p_provider_name := $INNER_BLOCK$||COALESCE(quote_literal(c_provider_name), 'NULL')||$INNER_BLOCK$, + p_set_name := ARRAY[$INNER_BLOCK$||quote_literal(c_set_name)||$INNER_BLOCK$], + p_nspname := $INNER_BLOCK$||COALESCE(quote_literal(v_nspname), 'NULL')::TEXT||$INNER_BLOCK$, + p_relname := $INNER_BLOCK$||COALESCE(quote_literal(v_relname), 'NULL')::TEXT||$INNER_BLOCK$, + p_ddl_sql_sent := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_ddl_sql_sent||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_full_ddl := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_full_ddl||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_pid := $INNER_BLOCK$||v_pid::TEXT||$INNER_BLOCK$, + p_set_config_id := $INNER_BLOCK$||c_set_config_id::TEXT||$INNER_BLOCK$, + p_queue_subscriber_failures := $INNER_BLOCK$||c_queue_subscriber_failures||$INNER_BLOCK$, + p_signal_blocking_subscriber_sessions := $INNER_BLOCK$||COALESCE(quote_literal(c_signal_blocking_subscriber_sessions),'NULL')||$INNER_BLOCK$, + p_lock_timeout := $INNER_BLOCK$||COALESCE(c_subscriber_lock_timeout, 3000)||$INNER_BLOCK$, + p_driver := $INNER_BLOCK$||quote_literal(c_driver)||$INNER_BLOCK$ + ); + $REPLICATE_DDL_COMMAND$, + --Pipe this DDL command through chosen replication set + ARRAY['$INNER_BLOCK$||c_set_name||$INNER_BLOCK$']); + $INNER_BLOCK$; + + RAISE DEBUG 'v_sql: %', v_sql; + EXECUTE v_sql; + + INSERT INTO pgl_ddl_deploy.events + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + ddl_sql_sent, + txid) + VALUES + (c_set_config_id, + c_set_name, + v_pid, + current_timestamp, + v_ddl_sql_raw, + v_ddl_sql_sent, + v_txid); + $BUILD$::TEXT AS shared_deploy_logic, + $BUILD$ + ELSEIF (v_match_count > 0 AND v_cmd_count <> v_match_count) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'mixed_objects', + v_txid); + $BUILD$::TEXT AS shared_mixed_obj_logic, + + $BUILD$ + /** + Catch any exceptions and log in a local table + As a safeguard, if even the exception handler fails, exit cleanly but add a server log message + **/ + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + v_context = PG_EXCEPTION_CONTEXT, + v_error = MESSAGE_TEXT, + v_error_detail = PG_EXCEPTION_DETAIL; + BEGIN + INSERT INTO pgl_ddl_deploy.exceptions (set_config_id, set_name, pid, executed_at, ddl_sql, err_msg, err_state) + VALUES (c_set_config_id, c_set_name, v_pid, current_timestamp, v_sql, format('%s %s %s', v_error, v_context, v_error_detail), SQLSTATE); + RAISE WARNING '%', c_exception_msg; + --No matter what, don't let this function block any DDL + EXCEPTION WHEN OTHERS THEN + RAISE WARNING 'Unhandled exception % %', SQLERRM, SQLSTATE; + END; + $BUILD$::TEXT AS shared_exception_handler, + + $BUILD$ + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* c_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = c_set_name + AND rsr.relid = c.oid + AND rsr.driver = c_driver) + $BUILD$::TEXT AS shared_repl_set_tables, + + $BUILD$ + SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name ~* c_include_schema_regex + AND schema_name !~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_include_schema_regex + AND object_identity !~* c_exclude_always) + ) + ) + OR + --include_only_repset_tables usage: + ( + ($BUILD$||include_only_repset_tables||$BUILD$) AND + (EXISTS + ( + SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.relid = c.objid + AND c.object_type in('table','table column','table constraint') + AND rsr.name = '$BUILD$||sc.set_name||$BUILD$' + AND rsr.driver = '$BUILD$||sc.driver||$BUILD$' + ) + ) + ) + THEN 1 + ELSE 0 END) AS match_count, + SUM(CASE + WHEN + --include_everything usage still excludes exclude_always regex: + ( + ($BUILD$||include_everything||$BUILD$) AND + ( + (schema_name ~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_exclude_always) + ) + ) + THEN 1 + ELSE 0 END) AS exclude_always_match_count + $BUILD$::TEXT AS shared_match_count +FROM pgl_ddl_deploy.rep_set_wrapper() rs +INNER JOIN pgl_ddl_deploy.set_configs sc ON sc.set_name = rs.name AND sc.driver = rs.driver +) + +, build AS ( +SELECT + id, + set_name, + include_schema_regex, + include_only_repset_tables, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + auto_replication_create_function_name, + auto_replication_drop_function_name, + auto_replication_unsupported_function_name, + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name, + +CASE WHEN driver = 'pglogical' THEN '--no-op pglogical diver'::TEXT +WHEN driver = 'native' THEN $BUILD$ +DO $$ +BEGIN + +IF NOT EXISTS (SELECT 1 +FROM pg_publication_tables +WHERE pubname = '$BUILD$||set_name||$BUILD$' +AND schemaname = 'pgl_ddl_deploy' +AND tablename = 'queue') THEN + ALTER PUBLICATION $BUILD$||quote_ident(set_name)||$BUILD$ + ADD TABLE pgl_ddl_deploy.queue; +END IF; + +END$$; +$BUILD$ +END AS add_queue_table_to_replication, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$ || auto_replication_create_function_name || $BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , MAX(c.schema_name) + , MAX(cl.relname) + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_nspname, v_relname + FROM pg_event_trigger_ddl_commands() c + LEFT JOIN LATERAL + (SELECT cl.relname + FROM pg_class cl + WHERE cl.oid = c.objid + AND c.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') + -- There should only be one table modified per event trigger + -- At least that's the best we will do now + LIMIT 1) cl ON TRUE; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_cmd_count = v_match_count)) + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension + FROM pg_event_trigger_ddl_commands(); + + /** + Add table to replication set immediately, if required, and only if the set_config includes CREATE TABLE. + We do not filter to tags here, because of possibility of multi-statement SQL. + Optional ddl_only_replication will never auto-add tables to replication because the + purpose is to only replicate keep the structure synchronized on the subscriber with no data. + **/ + IF c_create_tags && '{"CREATE TABLE"}' AND NOT $BUILD$||include_only_repset_tables||$BUILD$ AND NOT $BUILD$||ddl_only_replication||$BUILD$ THEN + PERFORM pgl_ddl_deploy.add_table_to_replication( + p_driver:=c_driver + ,p_set_name:=c_set_name + ,p_relation:=c.oid + ,p_synchronize_data:=false + ) + $BUILD$||shared_repl_set_tables||$BUILD$; + END IF; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$::TEXT +END AS auto_replication_function, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_drop_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name !~* '^(pg_catalog|pg_toast)$' + AND schema_name !~* c_include_schema_regex) + OR (object_type = 'schema' + AND object_identity !~* '^(pg_catalog|pg_toast)$' + AND object_identity !~* c_include_schema_regex) + ) + ) + --include_only_repset_tables cannot be used with DROP because + --the objects no longer exist to be checked: + THEN 1 + ELSE 0 END) AS excluded_count + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_excluded_count + FROM pg_event_trigger_dropped_objects() c; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_excluded_count = 0)) + + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + TG_TAG, + object_type, + schema_name, + object_identity, + NULL + FROM pg_event_trigger_dropped_objects(); + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_drop_function, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_unsupported_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + INTO v_cmd_count, v_match_count, v_exclude_always_match_count + FROM pg_event_trigger_ddl_commands() c; + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0) + THEN + + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'unsupported_command', + v_txid); + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_unsupported_function, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(create_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$ || auto_replication_create_function_name || $BUILD$(); +$BUILD$::TEXT +END AS auto_replication_trigger, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ON sql_drop +WHEN TAG IN('$BUILD$||array_to_string(drop_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$||auto_replication_drop_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_drop_trigger, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(pgl_ddl_deploy.unsupported_tags(),$$','$$)||$BUILD$') +EXECUTE PROCEDURE $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_unsupported_trigger, + +$BUILD$ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs (obj_type, obj_name) AS ( +VALUES +('EVENT TRIGGER','$BUILD$||auto_replication_create_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_drop_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_unsupported_trigger_name||$BUILD$'), +('FUNCTION','$BUILD$||auto_replication_create_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_drop_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_unsupported_function_name||$BUILD$()') +); + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; +DROP EVENT TRIGGER IF EXISTS $BUILD$||auto_replication_create_trigger_name||', '||auto_replication_drop_trigger_name||', '||auto_replication_unsupported_trigger_name||$BUILD$; +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_create_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_drop_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$ + AS undeploy_sql +FROM vars) + +SELECT + b.id, + b.set_name, + b.include_schema_regex, + b.include_only_repset_tables, + b.include_everything, + b.signal_blocking_subscriber_sessions, + b.subscriber_lock_timeout, + b.auto_replication_create_function_name, + b.auto_replication_drop_function_name, + b.auto_replication_unsupported_function_name, + b.auto_replication_create_trigger_name, + b.auto_replication_drop_trigger_name, + b.auto_replication_unsupported_trigger_name, + b.auto_replication_function, + b.auto_replication_drop_function, + b.auto_replication_unsupported_function, + b.auto_replication_trigger, + b.auto_replication_drop_trigger, + b.auto_replication_unsupported_trigger, + b.undeploy_sql, + b.undeploy_sql|| + b.add_queue_table_to_replication||$BUILD$ + $BUILD$||auto_replication_function||$BUILD$ + $BUILD$||auto_replication_drop_function||$BUILD$ + $BUILD$||auto_replication_unsupported_function||$BUILD$ + $BUILD$||auto_replication_trigger||$BUILD$ + $BUILD$||auto_replication_drop_trigger||$BUILD$ + $BUILD$||auto_replication_unsupported_trigger||$BUILD$ + SELECT pgl_ddl_deploy.add_ext_object(obj_type, obj_name) + FROM tmp_objs; + $BUILD$ AS deploy_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ DISABLE; + $BUILD$ AS disable_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ENABLE; + $BUILD$ AS enable_sql, + EXISTS (SELECT 1 + FROM pg_event_trigger + WHERE evtname IN( + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name + ) + AND evtenabled IN('O','R','A') + ) AS is_deployed +FROM build b; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.add_role(p_roleoid oid) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +/****** +Assuming roles doing DDL are not superusers, this function grants needed privileges +to run through the pgl_ddl_deploy DDL deployment. +This needs to be run on BOTH provider and subscriber. +******/ +DECLARE + v_rec RECORD; + v_sql TEXT; + v_rsat_args TEXT; +BEGIN + + FOR v_rec IN + SELECT quote_ident(rolname) AS rolname FROM pg_roles WHERE oid = p_roleoid + LOOP + + v_sql:=' + GRANT USAGE ON SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.replicate_ddl_command(text, text[]) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.add_table_to_replication(pgl_ddl_deploy.driver, name, regclass, boolean) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.notify_subscription_refresh(name, boolean) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.sql_command_tags(text) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, name, name) TO '||v_rec.rolname||'; + GRANT INSERT, UPDATE, SELECT ON ALL TABLES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||'; + GRANT USAGE ON ALL SEQUENCES IN SCHEMA pgl_ddl_deploy TO '||v_rec.rolname||';'; + EXECUTE v_sql; + + IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'pglogical') THEN + v_rsat_args:=pg_get_function_identity_arguments('pglogical.replication_set_add_table'::REGPROC); + + + v_sql:=' + GRANT USAGE ON SCHEMA pglogical TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replicate_ddl_command(text, text[]) TO '||v_rec.rolname||'; + GRANT EXECUTE ON FUNCTION pglogical.replication_set_add_table(' || v_rsat_args || ') TO '||v_rec.rolname||'; + GRANT SELECT ON ALL TABLES IN SCHEMA pglogical TO '||v_rec.rolname||';'; + EXECUTE v_sql; + END IF; + + RETURN true; + END LOOP; +RETURN false; +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.override() RETURNS BOOLEAN AS $BODY$ +BEGIN +RETURN FALSE; +END; +$BODY$ +LANGUAGE plpgsql IMMUTABLE; + + +-- Now re-deploy event triggers and functions +SELECT id, pgl_ddl_deploy.deploy(id) AS deployed +FROM ddl_deploy_to_refresh; + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +DROP TABLE IF EXISTS tmp_objs; + +-- Ensure added roles have write permissions for new tables added +-- Not so easy to pre-package this with default privileges because +-- we can't assume everyone uses the same role to deploy this extension +SELECT pgl_ddl_deploy.add_role(role_oid) +FROM ( +SELECT DISTINCT r.oid AS role_oid +FROM information_schema.table_privileges tp +INNER JOIN pg_roles r ON r.rolname = tp.grantee AND NOT r.rolsuper +WHERE table_schema = 'pgl_ddl_deploy' + AND privilege_type = 'INSERT' + AND table_name = 'subscriber_logs' +) roles_with_existing_privileges; + +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.add_table_to_replication(pgl_ddl_deploy.driver, name, regclass, boolean) FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.notify_subscription_refresh(name, boolean) FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, name, name) FROM PUBLIC; + + +/* pgl_ddl_deploy--2.0--2.1.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.execute_queued_ddl() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN + +/*** +Native logical replication does not support row filtering, so as a result, +we need to do processing downstream to ensure we only process rows we care about. + +For example, if we propagate some DDL to system 1 and some other to system 2, +all rows will still come through this trigger. We filter out rows based on +matching pubnames with pg_subscription.subpublications + +If a row arrives here (the subscriber), it must mean that it was propagated +***/ + +-- This handles potential duplicates with multiple subscriptions to same publisher db. +IF EXISTS ( +SELECT NEW.* +INTERSECT +SELECT * FROM pgl_ddl_deploy.queue) THEN + RETURN NULL; +END IF; + +IF NEW.message_type = pgl_ddl_deploy.queue_ddl_message_type() AND + (pgl_ddl_deploy.override() OR ((SELECT COUNT(1) FROM pg_subscription s + WHERE subpublications && NEW.pubnames) > 0)) THEN + + -- See https://www.postgresql.org/message-id/CAMa1XUh7ZVnBzORqjJKYOv4_pDSDUCvELRbkF0VtW7pvDW9rZw@mail.gmail.com + IF NEW.message ~* 'pgl_ddl_deploy.notify_subscription_refresh' THEN + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (NEW.pubnames[1], + NULL, + NULL, + NULL, + current_role, + pg_backend_pid(), + current_timestamp, + NEW.message, + NEW.message, + FALSE, + 'Unsupported automated ALTER SUBSCRIPTION ... REFRESH PUBLICATION until bugfix'); + ELSE + EXECUTE 'SET ROLE '||quote_ident(NEW.role)||';'; + EXECUTE NEW.message::TEXT; + END IF; + + RETURN NEW; +ELSE + RETURN NULL; +END IF; + +END; +$function$ +; + + +/* pgl_ddl_deploy--2.1--2.2.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +/* + * We need to re-deploy the trigger function definitions + * which will have changed with this extension update. So + * here we undeploy them, and save which ones we need to + * recreate later. +*/ +DO $$ +BEGIN + +IF EXISTS (SELECT 1 FROM pg_views WHERE schemaname = 'pgl_ddl_deploy' AND viewname = 'event_trigger_schema') THEN + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +CREATE TEMP TABLE ddl_deploy_to_refresh AS +SELECT id, pgl_ddl_deploy.undeploy(id) AS undeployed +FROM pgl_ddl_deploy.event_trigger_schema +WHERE is_deployed; + +-- it needs to be modified, so now we drop it to recreate later +DROP VIEW pgl_ddl_deploy.event_trigger_schema; + +ELSE + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +CREATE TEMP TABLE ddl_deploy_to_refresh AS +SELECT NULL::INT AS id; + +END IF; +END$$; + +DROP FUNCTION IF EXISTS pgl_ddl_deploy.get_altertable_subcmdinfo(pg_ddl_command); +DROP FUNCTION IF EXISTS pgl_ddl_deploy.get_altertable_subcmdtypes(pg_ddl_command); + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.execute_queued_ddl() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN + +/*** +Native logical replication does not support row filtering, so as a result, +we need to do processing downstream to ensure we only process rows we care about. + +For example, if we propagate some DDL to system 1 and some other to system 2, +all rows will still come through this trigger. We filter out rows based on +matching pubnames with pg_subscription.subpublications + +If a row arrives here (the subscriber), it must mean that it was propagated +***/ + +-- This handles potential duplicates with multiple subscriptions to same publisher db. +IF EXISTS ( +SELECT NEW.* +INTERSECT +SELECT * FROM pgl_ddl_deploy.queue) THEN + RETURN NULL; +END IF; + +IF NEW.message_type = pgl_ddl_deploy.queue_ddl_message_type() AND + (pgl_ddl_deploy.override() OR ((SELECT COUNT(1) FROM pg_subscription s + WHERE subpublications && NEW.pubnames) > 0)) THEN + + -- See https://www.postgresql.org/message-id/CAMa1XUh7ZVnBzORqjJKYOv4_pDSDUCvELRbkF0VtW7pvDW9rZw@mail.gmail.com + IF NEW.message ~* 'pgl_ddl_deploy.notify_subscription_refresh' THEN + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (NEW.pubnames[1], + NULL, + NULL, + NULL, + current_role, + pg_backend_pid(), + current_timestamp, + NEW.message, + NEW.message, + FALSE, + 'Unsupported automated ALTER SUBSCRIPTION ... REFRESH PUBLICATION until bugfix'); + ELSE + EXECUTE 'SET ROLE '||quote_ident(NEW.role)||';'; + EXECUTE NEW.message::TEXT; + END IF; + + RETURN NEW; +ELSE + RETURN NULL; +END IF; + +END; +$function$ +; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.get_altertable_subcmdinfo(pg_ddl_command) + RETURNS text[] IMMUTABLE STRICT + AS '$libdir/ddl_deparse', 'get_altertable_subcmdinfo' LANGUAGE C; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.subscriber_command +( + p_provider_name NAME, + p_set_name TEXT[], + p_nspname NAME, + p_relname NAME, + p_ddl_sql_sent TEXT, + p_full_ddl TEXT, + p_pid INT, + p_set_config_id INT, + p_queue_subscriber_failures BOOLEAN, + p_signal_blocking_subscriber_sessions pgl_ddl_deploy.signals, + p_lock_timeout INT, + p_driver pgl_ddl_deploy.driver, +-- This parameter currently only exists to make testing this function easier + p_run_anywhere BOOLEAN = FALSE +) +RETURNS BOOLEAN +AS $function$ +/**** +This function is what will actually be executed on the subscriber when attempting to apply DDL +changed. It is sent to subscriber(s) via pglogical.replicate_ddl_command. You can see how it +is called based on the the view pgl_ddl_deploy.event_trigger_schema, which is used to create the +specific event trigger functions that will call this function in different ways depending on +configuration in pgl_ddl_deploy.set_configs. + +This function is also used to make testing easier. The regression suite calls +this function to verify basic functionality. +****/ +DECLARE + v_succeeded BOOLEAN; + v_error_message TEXT; + v_attempt_number INT = 0; + v_signal pgl_ddl_deploy.signals; +BEGIN + +IF pgl_ddl_deploy.is_subscriber(p_driver, p_set_name, p_provider_name) OR p_run_anywhere THEN + + v_error_message = NULL; + /**** + If we have configured to kill blocking subscribers, here we set parameters for that: + 1. Whether to cancel or terminate + 2. What lock_timeout to tolerate + ****/ + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + v_signal = CASE WHEN p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' THEN 'cancel' ELSE p_signal_blocking_subscriber_sessions END; + -- We cannot RESET LOCAL lock_timeout but that should not be necessary because it will end with the transaction + EXECUTE format('SET LOCAL lock_timeout TO %s', p_lock_timeout); + END IF; + + /**** + Loop until one of the following takes place: + 1. Successful DDL execution on first attempt + 2. An unexpected ERROR occurs, which will either RAISE or finish with WARNING based on queue_subscriber_failures configuration + 3. Blocking sessions are killed until we finally get a successful DDL execution + ****/ + WHILE TRUE LOOP + BEGIN + + --Execute DDL + RAISE LOG 'pgl_ddl_deploy attempting execution: %', p_full_ddl; + + --Execute DDL - the reason we use execute here is partly to handle no trailing semicolon + EXECUTE p_full_ddl; + + v_succeeded = TRUE; + EXIT; + + EXCEPTION + WHEN lock_not_available THEN + IF p_signal_blocking_subscriber_sessions IS NOT NULL THEN + -- Change to terminate if we are using cancel_then_terminate and have not been successful after the first iteration + IF v_attempt_number > 0 AND p_signal_blocking_subscriber_sessions = 'cancel_then_terminate' AND v_signal = 'cancel' THEN + v_signal = 'terminate'; + END IF; + INSERT INTO pgl_ddl_deploy.killed_blockers + (signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported) + SELECT + signal, + successful, + pid, + executed_at, + usename, + client_addr, + xact_start, + state_change, + state, + query, + reported + FROM pgl_ddl_deploy.kill_blockers( + v_signal, + p_nspname, + p_relname + ); + + -- Continue and retry again but allow a brief pause + v_attempt_number = v_attempt_number + 1; + PERFORM pg_sleep(3); + ELSE + -- If p_signal_blocking_subscriber_sessions is not configured but we hit a lock_timeout, + -- then the replication user or cluster is configured with a global lock_timeout. Raise in this case. + RAISE; + END IF; + WHEN OTHERS THEN + IF p_queue_subscriber_failures THEN + RAISE WARNING 'Subscriber DDL failed with errors (see pgl_ddl_deploy.subscriber_logs): %', SQLERRM; + v_succeeded = FALSE; + v_error_message = SQLERRM; + EXIT; + ELSE + RAISE; + END IF; + END; + END LOOP; + + /**** + Since this function is only executed on the subscriber, this INSERT adds a log + to subscriber_logs on the subscriber after execution. + + Note that if we configured queue_subscriber_failures to TRUE in pgl_ddl_deploy.set_configs, then we are + allowing failed DDL to be caught and logged in this table as succeeded = FALSE for later processing. + ****/ + INSERT INTO pgl_ddl_deploy.subscriber_logs + (set_name, + provider_pid, + provider_node_name, + provider_set_config_id, + executed_as_role, + subscriber_pid, + executed_at, + ddl_sql, + full_ddl_sql, + succeeded, + error_message) + VALUES + (p_set_name, + p_pid, + p_provider_name, + p_set_config_id, + current_role, + pg_backend_pid(), + current_timestamp, + p_ddl_sql_sent, + p_full_ddl, + v_succeeded, + v_error_message); + +END IF; + +RETURN v_succeeded; + +END; +$function$ +LANGUAGE plpgsql VOLATILE; + + +CREATE OR REPLACE VIEW pgl_ddl_deploy.event_trigger_schema AS +WITH vars AS +(SELECT + sc.id, + set_name, + 'pgl_ddl_deploy.auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_function_name, + 'auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_trigger_name, + 'auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_trigger_name, + 'auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_trigger_name, + include_schema_regex, + include_only_repset_tables, + create_tags, + drop_tags, + ddl_only_replication, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + sc.driver, + + /**** + These constants in DECLARE portion of all functions is identical and can be shared + */ + $BUILD$ + c_search_path TEXT = (SELECT current_setting('search_path')); + c_provider_name TEXT; + --TODO: How do I decide which replication set we care about? + v_pid INT = pg_backend_pid(); + v_rec RECORD; + v_ddl_sql_raw TEXT; + v_ddl_sql_sent TEXT; + v_full_ddl TEXT; + v_sql_tags TEXT[]; + v_cmd_rec RECORD; + v_subcmd_rec RECORD; + v_excluded_subcommands TEXT; + v_contains_any_valid_subcommand INT; + + /***** + We need to strip the DDL of: + 1. Transaction begin and commit, which cannot run inside plpgsql + *****/ + v_ddl_strip_regex TEXT = '(begin\W*transaction\W*|begin\W*work\W*|begin\W*|commit\W*transaction\W*|commit\W*work\W*|commit\W*);'; + v_txid BIGINT; + v_ddl_length INT; + v_sql TEXT; + v_cmd_count INT; + v_match_count INT; + v_exclude_always_match_count INT; + v_nspname TEXT; + v_relname TEXT; + v_error TEXT; + v_error_detail TEXT; + v_context TEXT; + v_excluded_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_exception_msg TEXT = 'Deployment exception logged in pgl_ddl_deploy.exceptions'; + + --Configurable options in function setup + c_set_config_id INT = $BUILD$||sc.id::TEXT||$BUILD$; + -- Even though pglogical supports an array of sets, we only pipe DDL through one at a time + -- So c_set_name is a text not text[] data type. + c_set_name TEXT = '$BUILD$||set_name||$BUILD$'; + c_driver pgl_ddl_deploy.driver = '$BUILD$||sc.driver||$BUILD$'; + c_include_schema_regex TEXT = $BUILD$||COALESCE(''''||include_schema_regex||'''','NULL')||$BUILD$; + c_lock_safe_deployment BOOLEAN = $BUILD$||lock_safe_deployment||$BUILD$; + c_allow_multi_statements BOOLEAN = $BUILD$||allow_multi_statements||$BUILD$; + c_include_only_repset_tables BOOLEAN = $BUILD$||include_only_repset_tables||$BUILD$; + c_include_everything BOOLEAN = $BUILD$||include_everything||$BUILD$; + c_queue_subscriber_failures BOOLEAN = $BUILD$||queue_subscriber_failures||$BUILD$; + c_create_tags TEXT[] = '$BUILD$||create_tags::TEXT||$BUILD$'; + c_blacklisted_tags TEXT[] = '$BUILD$||blacklisted_tags::TEXT||$BUILD$'; + c_exclude_alter_table_subcommands TEXT[] = $BUILD$||COALESCE(quote_literal(exclude_alter_table_subcommands::TEXT),'NULL')||$BUILD$; + c_signal_blocking_subscriber_sessions TEXT = $BUILD$||COALESCE(quote_literal(signal_blocking_subscriber_sessions::TEXT),'NULL')||$BUILD$; + c_subscriber_lock_timeout INT = $BUILD$||COALESCE(subscriber_lock_timeout::TEXT,'NULL')||$BUILD$; + + --Constants based on configuration + c_exec_prefix TEXT =(CASE + WHEN c_lock_safe_deployment + THEN 'SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$' + ELSE '' + END); + c_exec_suffix TEXT = (CASE + WHEN c_lock_safe_deployment + THEN '$PGL_DDL_DEPLOY$);' + ELSE '' + END); + $BUILD$::TEXT AS declare_constants, + + $BUILD$ + --If there are any matches to our replication config, get the query + --This will either be sent, or logged at this point if not deployable + IF (c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0 THEN + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + v_txid = txid_current(); + END IF; + $BUILD$::TEXT AS shared_get_query, +/**** + This is the portion of the event trigger function that evaluates if SQL + is appropriate to propagate, and does propagate the event. It is shared + between the normal and drop event trigger functions. + */ + $BUILD$ + /**** + A multi-statement SQL command may fire this event trigger more than once + This check ensures the SQL is propagated only once, if at all + */ + IF EXISTS + (SELECT 1 FROM pgl_ddl_deploy.events + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + OR EXISTS + (SELECT 1 FROM pgl_ddl_deploy.unhandled + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + THEN + RETURN; + END IF; + + /**** + Get the command tags and reject blacklisted tags + */ + v_sql_tags:=(SELECT pgl_ddl_deploy.sql_command_tags(v_ddl_sql_raw)); + IF (SELECT c_blacklisted_tags && v_sql_tags) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_command_tags', + v_txid); + RETURN; + /**** + If we are not allowing multi-statements at all, reject + */ + ELSEIF (SELECT ARRAY[TG_TAG]::TEXT[] <> v_sql_tags WHERE NOT c_allow_multi_statements) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_multi_statement', + v_txid); + RETURN; + END IF; + + /**** + If this is an ALTER TABLE statement and we are excluding any subcommand tags, process now. + Note the following. + + Because there can be more than one subcommand, we have a limited ability + to filter out subcommands until such a time as we may have a mechanism for rebuilding only + the SQL we want. In other words, if we have one subcommand that we DO want (i.e. ADD COLUMN) + and one we don't want (i.e. REFERENCES) in the same SQL, and we are "excluding" the latter, + we can't do that exclusion safely because we WANT the ADD COLUMN statement. In such a case, + we are still going to allow the DDL to go through because it's better to break replication than + miss a column addition. + + But if the only subcommand is an excluded one, i.e. ADD CONSTRAINT, then we will indeed ignore + the DDL and the function will RETURN without executing replicate_ddl_command. + */ + IF TG_TAG = 'ALTER TABLE' AND c_exclude_alter_table_subcommands IS NOT NULL THEN + FOR v_cmd_rec IN + SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF pgl_ddl_deploy.get_command_type(v_cmd_rec.command) = 'alter table' THEN + WITH subcommands AS ( + SELECT subcommand, + c_exclude_alter_table_subcommands && ARRAY[subcommand] AS subcommand_is_excluded, + MAX(CASE WHEN c_exclude_alter_table_subcommands && ARRAY[subcommand] THEN 0 ELSE 1 END) OVER() AS contains_any_valid_subcommand + FROM unnest(pgl_ddl_deploy.get_altertable_subcmdinfo(v_cmd_rec.command)) AS subcommand + ) + + SELECT (SELECT string_agg(subcommand,', ') FROM subcommands WHERE subcommand_is_excluded), + (SELECT contains_any_valid_subcommand FROM subcommands LIMIT 1) + INTO v_excluded_subcommands, + v_contains_any_valid_subcommand; + IF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 0 THEN + RAISE LOG 'Not processing DDL due to excluded subcommand(s): %: %', v_excluded_subcommands, v_ddl_sql_raw; + RETURN; + ELSEIF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 1 THEN + RAISE WARNING $INNER_BLOCK$Filtering out more than one subcommand in one ALTER TABLE is not supported. + Allowing to proceed: Rejected: %, SQL: %$INNER_BLOCK$, v_excluded_subcommands, v_ddl_sql_raw; + END IF; + END IF; + END LOOP; + END IF; + + v_ddl_sql_sent = v_ddl_sql_raw; + + --If there are BEGIN/COMMIT tags, attempt to strip and reparse + IF (SELECT ARRAY['BEGIN','COMMIT']::TEXT[] && v_sql_tags) THEN + v_ddl_sql_sent = regexp_replace(v_ddl_sql_sent, v_ddl_strip_regex, '', 'ig'); + + --Sanity reparse + PERFORM pgl_ddl_deploy.sql_command_tags(v_ddl_sql_sent); + END IF; + + --Get provider name, in order only to run command on a subscriber to this provider + c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); + + /* + Build replication DDL command which will conditionally run only on the subscriber + In other words, this MUST be a no-op on the provider + **Because the DDL has already run at this point (ddl_command_end)** + */ + v_full_ddl:=$INNER_BLOCK$ + --Be sure to use provider's search_path for SQL environment consistency + SET SEARCH_PATH TO $INNER_BLOCK$|| + CASE WHEN COALESCE(c_search_path,'') IN('','""') THEN quote_literal('') ELSE c_search_path END||$INNER_BLOCK$; + + $INNER_BLOCK$||c_exec_prefix||v_ddl_sql_sent||c_exec_suffix||$INNER_BLOCK$ + ; + $INNER_BLOCK$; + RAISE DEBUG 'v_full_ddl: %', v_full_ddl; + RAISE DEBUG 'c_set_config_id: %', c_set_config_id; + RAISE DEBUG 'c_set_name: %', c_set_name; + RAISE DEBUG 'c_driver: %', c_driver; + RAISE DEBUG 'v_ddl_sql_sent: %', v_ddl_sql_sent; + + v_sql:=$INNER_BLOCK$ + SELECT $BUILD$||CASE + WHEN sc.driver = 'native' + THEN 'pgl_ddl_deploy' + WHEN sc.driver = 'pglogical' + THEN 'pglogical' + ELSE 'ERROR-EXCEPTION' END||$BUILD$.replicate_ddl_command($REPLICATE_DDL_COMMAND$ + SELECT pgl_ddl_deploy.subscriber_command + ( + p_provider_name := $INNER_BLOCK$||COALESCE(quote_literal(c_provider_name), 'NULL')||$INNER_BLOCK$, + p_set_name := ARRAY[$INNER_BLOCK$||quote_literal(c_set_name)||$INNER_BLOCK$], + p_nspname := $INNER_BLOCK$||COALESCE(quote_literal(v_nspname), 'NULL')::TEXT||$INNER_BLOCK$, + p_relname := $INNER_BLOCK$||COALESCE(quote_literal(v_relname), 'NULL')::TEXT||$INNER_BLOCK$, + p_ddl_sql_sent := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_ddl_sql_sent||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_full_ddl := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_full_ddl||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_pid := $INNER_BLOCK$||v_pid::TEXT||$INNER_BLOCK$, + p_set_config_id := $INNER_BLOCK$||c_set_config_id::TEXT||$INNER_BLOCK$, + p_queue_subscriber_failures := $INNER_BLOCK$||c_queue_subscriber_failures||$INNER_BLOCK$, + p_signal_blocking_subscriber_sessions := $INNER_BLOCK$||COALESCE(quote_literal(c_signal_blocking_subscriber_sessions),'NULL')||$INNER_BLOCK$, + p_lock_timeout := $INNER_BLOCK$||COALESCE(c_subscriber_lock_timeout, 3000)||$INNER_BLOCK$, + p_driver := $INNER_BLOCK$||quote_literal(c_driver)||$INNER_BLOCK$ + ); + $REPLICATE_DDL_COMMAND$, + --Pipe this DDL command through chosen replication set + ARRAY['$INNER_BLOCK$||c_set_name||$INNER_BLOCK$']); + $INNER_BLOCK$; + + RAISE DEBUG 'v_sql: %', v_sql; + EXECUTE v_sql; + + INSERT INTO pgl_ddl_deploy.events + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + ddl_sql_sent, + txid) + VALUES + (c_set_config_id, + c_set_name, + v_pid, + current_timestamp, + v_ddl_sql_raw, + v_ddl_sql_sent, + v_txid); + $BUILD$::TEXT AS shared_deploy_logic, + $BUILD$ + ELSEIF (v_match_count > 0 AND v_cmd_count <> v_match_count) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'mixed_objects', + v_txid); + $BUILD$::TEXT AS shared_mixed_obj_logic, + + $BUILD$ + /** + Catch any exceptions and log in a local table + As a safeguard, if even the exception handler fails, exit cleanly but add a server log message + **/ + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + v_context = PG_EXCEPTION_CONTEXT, + v_error = MESSAGE_TEXT, + v_error_detail = PG_EXCEPTION_DETAIL; + BEGIN + INSERT INTO pgl_ddl_deploy.exceptions (set_config_id, set_name, pid, executed_at, ddl_sql, err_msg, err_state) + VALUES (c_set_config_id, c_set_name, v_pid, current_timestamp, v_sql, format('%s %s %s', v_error, v_context, v_error_detail), SQLSTATE); + RAISE WARNING '%', c_exception_msg; + --No matter what, don't let this function block any DDL + EXCEPTION WHEN OTHERS THEN + RAISE WARNING 'Unhandled exception % %', SQLERRM, SQLSTATE; + END; + $BUILD$::TEXT AS shared_exception_handler, + + $BUILD$ + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* c_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = c_set_name + AND rsr.relid = c.oid + AND rsr.driver = c_driver) + $BUILD$::TEXT AS shared_repl_set_tables, + + $BUILD$ + SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name ~* c_include_schema_regex + AND schema_name !~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_include_schema_regex + AND object_identity !~* c_exclude_always) + ) + ) + OR + --include_only_repset_tables usage: + ( + ($BUILD$||include_only_repset_tables||$BUILD$) AND + (EXISTS + ( + SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.relid = c.objid + AND c.object_type in('table','table column','table constraint') + AND rsr.name = '$BUILD$||sc.set_name||$BUILD$' + AND rsr.driver = '$BUILD$||sc.driver||$BUILD$' + ) + ) + ) + THEN 1 + ELSE 0 END) AS match_count, + SUM(CASE + WHEN + --include_everything usage still excludes exclude_always regex: + ( + ($BUILD$||include_everything||$BUILD$) AND + ( + (schema_name ~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_exclude_always) + ) + ) + THEN 1 + ELSE 0 END) AS exclude_always_match_count + $BUILD$::TEXT AS shared_match_count +FROM pgl_ddl_deploy.rep_set_wrapper() rs +INNER JOIN pgl_ddl_deploy.set_configs sc ON sc.set_name = rs.name AND sc.driver = rs.driver +) + +, build AS ( +SELECT + id, + set_name, + include_schema_regex, + include_only_repset_tables, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + auto_replication_create_function_name, + auto_replication_drop_function_name, + auto_replication_unsupported_function_name, + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name, + +CASE WHEN driver = 'pglogical' THEN '--no-op pglogical diver'::TEXT +WHEN driver = 'native' THEN $BUILD$ +DO $$ +BEGIN + +IF NOT EXISTS (SELECT 1 +FROM pg_publication_tables +WHERE pubname = '$BUILD$||set_name||$BUILD$' +AND schemaname = 'pgl_ddl_deploy' +AND tablename = 'queue') THEN + ALTER PUBLICATION $BUILD$||quote_ident(set_name)||$BUILD$ + ADD TABLE pgl_ddl_deploy.queue; +END IF; + +END$$; +$BUILD$ +END AS add_queue_table_to_replication, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$ || auto_replication_create_function_name || $BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , MAX(c.schema_name) + , MAX(cl.relname) + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_nspname, v_relname + FROM pg_event_trigger_ddl_commands() c + LEFT JOIN LATERAL + (SELECT cl.relname + FROM pg_class cl + WHERE cl.oid = c.objid + AND c.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') + -- There should only be one table modified per event trigger + -- At least that's the best we will do now + LIMIT 1) cl ON TRUE; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_cmd_count = v_match_count)) + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension + FROM pg_event_trigger_ddl_commands(); + + /** + Add table to replication set immediately, if required, and only if the set_config includes CREATE TABLE. + We do not filter to tags here, because of possibility of multi-statement SQL. + Optional ddl_only_replication will never auto-add tables to replication because the + purpose is to only replicate keep the structure synchronized on the subscriber with no data. + **/ + IF c_create_tags && '{"CREATE TABLE"}' AND NOT $BUILD$||include_only_repset_tables||$BUILD$ AND NOT $BUILD$||ddl_only_replication||$BUILD$ THEN + PERFORM pgl_ddl_deploy.add_table_to_replication( + p_driver:=c_driver + ,p_set_name:=c_set_name + ,p_relation:=c.oid + ,p_synchronize_data:=false + ) + $BUILD$||shared_repl_set_tables||$BUILD$; + END IF; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$::TEXT +END AS auto_replication_function, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_drop_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name !~* '^(pg_catalog|pg_toast)$' + AND schema_name !~* c_include_schema_regex) + OR (object_type = 'schema' + AND object_identity !~* '^(pg_catalog|pg_toast)$' + AND object_identity !~* c_include_schema_regex) + ) + ) + --include_only_repset_tables cannot be used with DROP because + --the objects no longer exist to be checked: + THEN 1 + ELSE 0 END) AS excluded_count + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_excluded_count + FROM pg_event_trigger_dropped_objects() c; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_excluded_count = 0)) + + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + TG_TAG, + object_type, + schema_name, + object_identity, + NULL + FROM pg_event_trigger_dropped_objects(); + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_drop_function, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_unsupported_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + INTO v_cmd_count, v_match_count, v_exclude_always_match_count + FROM pg_event_trigger_ddl_commands() c; + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0) + THEN + + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'unsupported_command', + v_txid); + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_unsupported_function, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(create_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$ || auto_replication_create_function_name || $BUILD$(); +$BUILD$::TEXT +END AS auto_replication_trigger, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ON sql_drop +WHEN TAG IN('$BUILD$||array_to_string(drop_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$||auto_replication_drop_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_drop_trigger, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(pgl_ddl_deploy.unsupported_tags(),$$','$$)||$BUILD$') +EXECUTE PROCEDURE $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_unsupported_trigger, + +$BUILD$ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs (obj_type, obj_name) AS ( +VALUES +('EVENT TRIGGER','$BUILD$||auto_replication_create_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_drop_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_unsupported_trigger_name||$BUILD$'), +('FUNCTION','$BUILD$||auto_replication_create_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_drop_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_unsupported_function_name||$BUILD$()') +); + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; +DROP EVENT TRIGGER IF EXISTS $BUILD$||auto_replication_create_trigger_name||', '||auto_replication_drop_trigger_name||', '||auto_replication_unsupported_trigger_name||$BUILD$; +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_create_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_drop_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$ + AS undeploy_sql +FROM vars) + +SELECT + b.id, + b.set_name, + b.include_schema_regex, + b.include_only_repset_tables, + b.include_everything, + b.signal_blocking_subscriber_sessions, + b.subscriber_lock_timeout, + b.auto_replication_create_function_name, + b.auto_replication_drop_function_name, + b.auto_replication_unsupported_function_name, + b.auto_replication_create_trigger_name, + b.auto_replication_drop_trigger_name, + b.auto_replication_unsupported_trigger_name, + b.auto_replication_function, + b.auto_replication_drop_function, + b.auto_replication_unsupported_function, + b.auto_replication_trigger, + b.auto_replication_drop_trigger, + b.auto_replication_unsupported_trigger, + b.undeploy_sql, + b.undeploy_sql|| + b.add_queue_table_to_replication||$BUILD$ + $BUILD$||auto_replication_function||$BUILD$ + $BUILD$||auto_replication_drop_function||$BUILD$ + $BUILD$||auto_replication_unsupported_function||$BUILD$ + $BUILD$||auto_replication_trigger||$BUILD$ + $BUILD$||auto_replication_drop_trigger||$BUILD$ + $BUILD$||auto_replication_unsupported_trigger||$BUILD$ + SELECT pgl_ddl_deploy.add_ext_object(obj_type, obj_name) + FROM tmp_objs; + $BUILD$ AS deploy_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ DISABLE; + $BUILD$ AS disable_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ENABLE; + $BUILD$ AS enable_sql, + EXISTS (SELECT 1 + FROM pg_event_trigger + WHERE evtname IN( + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name + ) + AND evtenabled IN('O','R','A') + ) AS is_deployed +FROM build b; + + +-- Now re-deploy event triggers and functions +SELECT id, pgl_ddl_deploy.deploy(id) AS deployed +FROM ddl_deploy_to_refresh; + +DROP TABLE IF EXISTS ddl_deploy_to_refresh; +DROP TABLE IF EXISTS tmp_objs; + +-- Ensure added roles have write permissions for new tables added +-- Not so easy to pre-package this with default privileges because +-- we can't assume everyone uses the same role to deploy this extension +SELECT pgl_ddl_deploy.add_role(role_oid) +FROM ( +SELECT DISTINCT r.oid AS role_oid +FROM information_schema.table_privileges tp +INNER JOIN pg_roles r ON r.rolname = tp.grantee AND NOT r.rolsuper +WHERE table_schema = 'pgl_ddl_deploy' + AND privilege_type = 'INSERT' + AND table_name = 'subscriber_logs' +) roles_with_existing_privileges; + +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.add_table_to_replication(pgl_ddl_deploy.driver, name, regclass, boolean) FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.notify_subscription_refresh(name, boolean) FROM PUBLIC; +REVOKE EXECUTE ON FUNCTION pgl_ddl_deploy.kill_blockers(pgl_ddl_deploy.signals, name, name) FROM PUBLIC; + + +/* pgl_ddl_deploy--2.2--2.3.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +CREATE OR REPLACE VIEW pgl_ddl_deploy.event_trigger_schema AS +WITH vars AS +(SELECT + sc.id, + set_name, + 'pgl_ddl_deploy.auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_function_name, + 'auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_trigger_name, + 'auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_trigger_name, + 'auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_trigger_name, + include_schema_regex, + include_only_repset_tables, + create_tags, + drop_tags, + ddl_only_replication, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + sc.driver, + + /**** + These constants in DECLARE portion of all functions is identical and can be shared + */ + $BUILD$ + c_search_path TEXT = (SELECT current_setting('search_path')); + c_provider_name TEXT; + --TODO: How do I decide which replication set we care about? + v_pid INT = pg_backend_pid(); + v_rec RECORD; + v_ddl_sql_raw TEXT; + v_ddl_sql_sent TEXT; + v_full_ddl TEXT; + v_sql_tags TEXT[]; + v_cmd_rec RECORD; + v_subcmd_rec RECORD; + v_excluded_subcommands TEXT; + v_contains_any_valid_subcommand INT; + + /***** + We need to strip the DDL of: + 1. Transaction begin and commit, which cannot run inside plpgsql + *****/ + v_ddl_strip_regex TEXT = '(begin\W*transaction\W*|begin\W*work\W*|begin\W*|commit\W*transaction\W*|commit\W*work\W*|commit\W*);'; + v_txid BIGINT; + v_ddl_length INT; + v_sql TEXT; + v_cmd_count INT; + v_match_count INT; + v_exclude_always_match_count INT; + v_nspname TEXT; + v_relname TEXT; + v_error TEXT; + v_error_detail TEXT; + v_context TEXT; + v_excluded_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_exception_msg TEXT = 'Deployment exception logged in pgl_ddl_deploy.exceptions'; + + --Configurable options in function setup + c_set_config_id INT = $BUILD$||sc.id::TEXT||$BUILD$; + -- Even though pglogical supports an array of sets, we only pipe DDL through one at a time + -- So c_set_name is a text not text[] data type. + c_set_name TEXT = '$BUILD$||set_name||$BUILD$'; + c_driver pgl_ddl_deploy.driver = '$BUILD$||sc.driver||$BUILD$'; + c_include_schema_regex TEXT = $BUILD$||COALESCE(''''||include_schema_regex||'''','NULL')||$BUILD$; + c_lock_safe_deployment BOOLEAN = $BUILD$||lock_safe_deployment||$BUILD$; + c_allow_multi_statements BOOLEAN = $BUILD$||allow_multi_statements||$BUILD$; + c_include_only_repset_tables BOOLEAN = $BUILD$||include_only_repset_tables||$BUILD$; + c_include_everything BOOLEAN = $BUILD$||include_everything||$BUILD$; + c_queue_subscriber_failures BOOLEAN = $BUILD$||queue_subscriber_failures||$BUILD$; + c_create_tags TEXT[] = '$BUILD$||create_tags::TEXT||$BUILD$'; + c_blacklisted_tags TEXT[] = '$BUILD$||blacklisted_tags::TEXT||$BUILD$'; + c_exclude_alter_table_subcommands TEXT[] = $BUILD$||COALESCE(quote_literal(exclude_alter_table_subcommands::TEXT),'NULL')||$BUILD$; + c_signal_blocking_subscriber_sessions TEXT = $BUILD$||COALESCE(quote_literal(signal_blocking_subscriber_sessions::TEXT),'NULL')||$BUILD$; + c_subscriber_lock_timeout INT = $BUILD$||COALESCE(subscriber_lock_timeout::TEXT,'NULL')||$BUILD$; + + --Constants based on configuration + c_exec_prefix TEXT =(CASE + WHEN c_lock_safe_deployment + THEN 'SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$' + ELSE '' + END); + c_exec_suffix TEXT = (CASE + WHEN c_lock_safe_deployment + THEN '$PGL_DDL_DEPLOY$);' + ELSE '' + END); + $BUILD$::TEXT AS declare_constants, + + $BUILD$ + --If there are any matches to our replication config, get the query + --This will either be sent, or logged at this point if not deployable + IF (c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0 THEN + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + v_txid = txid_current(); + END IF; + $BUILD$::TEXT AS shared_get_query, +/**** + This is the portion of the event trigger function that evaluates if SQL + is appropriate to propagate, and does propagate the event. It is shared + between the normal and drop event trigger functions. + */ + $BUILD$ + /**** + A multi-statement SQL command may fire this event trigger more than once + This check ensures the SQL is propagated only once, if at all + */ + IF EXISTS + (SELECT 1 FROM pgl_ddl_deploy.events + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + OR EXISTS + (SELECT 1 FROM pgl_ddl_deploy.unhandled + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + THEN + RETURN; + END IF; + + /**** + Get the command tags and reject blacklisted tags + */ + v_sql_tags:=(SELECT pgl_ddl_deploy.sql_command_tags(v_ddl_sql_raw)); + IF (SELECT c_blacklisted_tags && v_sql_tags) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_command_tags', + v_txid); + RETURN; + /**** + If we are not allowing multi-statements at all, reject + */ + ELSEIF (SELECT ARRAY[TG_TAG]::TEXT[] <> v_sql_tags WHERE NOT c_allow_multi_statements) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_multi_statement', + v_txid); + RETURN; + END IF; + + /**** + If this is an ALTER TABLE statement and we are excluding any subcommand tags, process now. + Note the following. + + Because there can be more than one subcommand, we have a limited ability + to filter out subcommands until such a time as we may have a mechanism for rebuilding only + the SQL we want. In other words, if we have one subcommand that we DO want (i.e. ADD COLUMN) + and one we don't want (i.e. REFERENCES) in the same SQL, and we are "excluding" the latter, + we can't do that exclusion safely because we WANT the ADD COLUMN statement. In such a case, + we are still going to allow the DDL to go through because it's better to break replication than + miss a column addition. + + But if the only subcommand is an excluded one, i.e. ADD CONSTRAINT, then we will indeed ignore + the DDL and the function will RETURN without executing replicate_ddl_command. + */ + IF TG_TAG = 'ALTER TABLE' AND c_exclude_alter_table_subcommands IS NOT NULL THEN + FOR v_cmd_rec IN + SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF pgl_ddl_deploy.get_command_type(v_cmd_rec.command) = 'alter table' THEN + WITH subcommands AS ( + SELECT subcommand, + c_exclude_alter_table_subcommands && ARRAY[subcommand] AS subcommand_is_excluded, + MAX(CASE WHEN c_exclude_alter_table_subcommands && ARRAY[subcommand] THEN 0 ELSE 1 END) OVER() AS contains_any_valid_subcommand + FROM unnest(pgl_ddl_deploy.get_altertable_subcmdinfo(v_cmd_rec.command)) AS subcommand + ) + + SELECT (SELECT string_agg(subcommand,', ') FROM subcommands WHERE subcommand_is_excluded), + (SELECT contains_any_valid_subcommand FROM subcommands LIMIT 1) + INTO v_excluded_subcommands, + v_contains_any_valid_subcommand; + IF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 0 THEN + RAISE LOG 'Not processing DDL due to excluded subcommand(s): %: %', v_excluded_subcommands, v_ddl_sql_raw; + RETURN; + ELSEIF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 1 THEN + RAISE WARNING $INNER_BLOCK$Filtering out more than one subcommand in one ALTER TABLE is not supported. + Allowing to proceed: Rejected: %, SQL: %$INNER_BLOCK$, v_excluded_subcommands, v_ddl_sql_raw; + END IF; + END IF; + END LOOP; + END IF; + + v_ddl_sql_sent = v_ddl_sql_raw; + + --If there are BEGIN/COMMIT tags, attempt to strip and reparse + IF (SELECT ARRAY['BEGIN','COMMIT']::TEXT[] && v_sql_tags) THEN + v_ddl_sql_sent = regexp_replace(v_ddl_sql_sent, v_ddl_strip_regex, '', 'ig'); + + --Sanity reparse + PERFORM pgl_ddl_deploy.sql_command_tags(v_ddl_sql_sent); + END IF; + + --Get provider name, in order only to run command on a subscriber to this provider + c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); + + /* + Build replication DDL command which will conditionally run only on the subscriber + In other words, this MUST be a no-op on the provider + **Because the DDL has already run at this point (ddl_command_end)** + */ + v_full_ddl:=$INNER_BLOCK$ + --Be sure to use provider's search_path for SQL environment consistency + SET SEARCH_PATH TO $INNER_BLOCK$|| + CASE WHEN COALESCE(c_search_path,'') IN('','""') THEN quote_literal('') ELSE c_search_path END||$INNER_BLOCK$; + + $INNER_BLOCK$||c_exec_prefix||v_ddl_sql_sent||c_exec_suffix||$INNER_BLOCK$ + ; + $INNER_BLOCK$; + RAISE DEBUG 'v_full_ddl: %', v_full_ddl; + RAISE DEBUG 'c_set_config_id: %', c_set_config_id; + RAISE DEBUG 'c_set_name: %', c_set_name; + RAISE DEBUG 'c_driver: %', c_driver; + RAISE DEBUG 'v_ddl_sql_sent: %', v_ddl_sql_sent; + + v_sql:=$INNER_BLOCK$ + SELECT $BUILD$||CASE + WHEN sc.driver = 'native' + THEN 'pgl_ddl_deploy' + WHEN sc.driver = 'pglogical' + THEN 'pglogical' + ELSE 'ERROR-EXCEPTION' END||$BUILD$.replicate_ddl_command($REPLICATE_DDL_COMMAND$ + SELECT pgl_ddl_deploy.subscriber_command + ( + p_provider_name := $INNER_BLOCK$||COALESCE(quote_literal(c_provider_name), 'NULL')||$INNER_BLOCK$, + p_set_name := ARRAY[$INNER_BLOCK$||quote_literal(c_set_name)||$INNER_BLOCK$], + p_nspname := $INNER_BLOCK$||COALESCE(quote_literal(v_nspname), 'NULL')::TEXT||$INNER_BLOCK$, + p_relname := $INNER_BLOCK$||COALESCE(quote_literal(v_relname), 'NULL')::TEXT||$INNER_BLOCK$, + p_ddl_sql_sent := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_ddl_sql_sent||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_full_ddl := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_full_ddl||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_pid := $INNER_BLOCK$||v_pid::TEXT||$INNER_BLOCK$, + p_set_config_id := $INNER_BLOCK$||c_set_config_id::TEXT||$INNER_BLOCK$, + p_queue_subscriber_failures := $INNER_BLOCK$||c_queue_subscriber_failures||$INNER_BLOCK$, + p_signal_blocking_subscriber_sessions := $INNER_BLOCK$||COALESCE(quote_literal(c_signal_blocking_subscriber_sessions),'NULL')||$INNER_BLOCK$, + p_lock_timeout := $INNER_BLOCK$||COALESCE(c_subscriber_lock_timeout, 3000)||$INNER_BLOCK$, + p_driver := $INNER_BLOCK$||quote_literal(c_driver)||$INNER_BLOCK$ + ); + $REPLICATE_DDL_COMMAND$, + --Pipe this DDL command through chosen replication set + ARRAY['$INNER_BLOCK$||c_set_name||$INNER_BLOCK$']); + $INNER_BLOCK$; + + RAISE DEBUG 'v_sql: %', v_sql; + EXECUTE v_sql; + + INSERT INTO pgl_ddl_deploy.events + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + ddl_sql_sent, + txid) + VALUES + (c_set_config_id, + c_set_name, + v_pid, + current_timestamp, + v_ddl_sql_raw, + v_ddl_sql_sent, + v_txid); + $BUILD$::TEXT AS shared_deploy_logic, + $BUILD$ + ELSEIF (v_match_count > 0 AND v_cmd_count <> v_match_count) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'mixed_objects', + v_txid); + $BUILD$::TEXT AS shared_mixed_obj_logic, + $BUILD$ + -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + $BUILD$::TEXT AS dropped_objects_query, + + $BUILD$ + /** + Catch any exceptions and log in a local table + As a safeguard, if even the exception handler fails, exit cleanly but add a server log message + **/ + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + v_context = PG_EXCEPTION_CONTEXT, + v_error = MESSAGE_TEXT, + v_error_detail = PG_EXCEPTION_DETAIL; + BEGIN + INSERT INTO pgl_ddl_deploy.exceptions (set_config_id, set_name, pid, executed_at, ddl_sql, err_msg, err_state) + VALUES (c_set_config_id, c_set_name, v_pid, current_timestamp, v_sql, format('%s %s %s', v_error, v_context, v_error_detail), SQLSTATE); + RAISE WARNING '% (%: % - %)', c_exception_msg, v_error, v_context, v_error_detail; + --No matter what, don't let this function block any DDL + EXCEPTION WHEN OTHERS THEN + RAISE WARNING 'Unhandled exception % %', SQLERRM, SQLSTATE; + END; + $BUILD$::TEXT AS shared_exception_handler, + + $BUILD$ + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* c_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = c_set_name + AND rsr.relid = c.oid + AND rsr.driver = c_driver) + $BUILD$::TEXT AS shared_repl_set_tables, + + $BUILD$ + SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name ~* c_include_schema_regex + AND schema_name !~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_include_schema_regex + AND object_identity !~* c_exclude_always) + ) + ) + OR + --include_only_repset_tables usage: + ( + ($BUILD$||include_only_repset_tables||$BUILD$) AND + (EXISTS + ( + SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.relid = c.objid + AND c.object_type in('table','table column','table constraint') + AND rsr.name = '$BUILD$||sc.set_name||$BUILD$' + AND rsr.driver = '$BUILD$||sc.driver||$BUILD$' + ) + ) + ) + THEN 1 + ELSE 0 END) AS match_count, + SUM(CASE + WHEN + --include_everything usage still excludes exclude_always regex: + ( + ($BUILD$||include_everything||$BUILD$) AND + ( + (schema_name ~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_exclude_always) + ) + ) + THEN 1 + ELSE 0 END) AS exclude_always_match_count + $BUILD$::TEXT AS shared_match_count +FROM pgl_ddl_deploy.rep_set_wrapper() rs +INNER JOIN pgl_ddl_deploy.set_configs sc ON sc.set_name = rs.name AND sc.driver = rs.driver +) + +, build AS ( +SELECT + id, + set_name, + include_schema_regex, + include_only_repset_tables, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + auto_replication_create_function_name, + auto_replication_drop_function_name, + auto_replication_unsupported_function_name, + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name, + +CASE WHEN driver = 'pglogical' THEN '--no-op pglogical diver'::TEXT +WHEN driver = 'native' THEN $BUILD$ +DO $$ +BEGIN + +IF NOT EXISTS (SELECT 1 +FROM pg_publication_tables +WHERE pubname = '$BUILD$||set_name||$BUILD$' +AND schemaname = 'pgl_ddl_deploy' +AND tablename = 'queue') THEN + ALTER PUBLICATION $BUILD$||quote_ident(set_name)||$BUILD$ + ADD TABLE pgl_ddl_deploy.queue; +END IF; + +END$$; +$BUILD$ +END AS add_queue_table_to_replication, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$ || auto_replication_create_function_name || $BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , MAX(c.schema_name) + , MAX(cl.relname) + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_nspname, v_relname + FROM pg_event_trigger_ddl_commands() c + LEFT JOIN LATERAL + (SELECT cl.relname + FROM pg_class cl + WHERE cl.oid = c.objid + AND c.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') + -- There should only be one table modified per event trigger + -- At least that's the best we will do now + LIMIT 1) cl ON TRUE; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_cmd_count = v_match_count)) + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension + FROM pg_event_trigger_ddl_commands(); + + /** + Add table to replication set immediately, if required, and only if the set_config includes CREATE TABLE. + We do not filter to tags here, because of possibility of multi-statement SQL. + Optional ddl_only_replication will never auto-add tables to replication because the + purpose is to only replicate keep the structure synchronized on the subscriber with no data. + **/ + IF c_create_tags && '{"CREATE TABLE"}' AND NOT $BUILD$||include_only_repset_tables||$BUILD$ AND NOT $BUILD$||ddl_only_replication||$BUILD$ THEN + PERFORM pgl_ddl_deploy.add_table_to_replication( + p_driver:=c_driver + ,p_set_name:=c_set_name + ,p_relation:=c.oid + ,p_synchronize_data:=false + ) + $BUILD$||shared_repl_set_tables||$BUILD$; + END IF; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$::TEXT +END AS auto_replication_function, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_drop_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name !~* '^(pg_catalog|pg_toast)$' + AND schema_name !~* c_include_schema_regex) + OR (object_type = 'schema' + AND object_identity !~* '^(pg_catalog|pg_toast)$' + AND object_identity !~* c_include_schema_regex) + ) + ) + --include_only_repset_tables cannot be used with DROP because + --the objects no longer exist to be checked: + THEN 1 + ELSE 0 END) AS excluded_count + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_excluded_count + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_excluded_count = 0)) + + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + TG_TAG, + object_type, + schema_name, + object_identity, + NULL + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_drop_function, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_unsupported_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + INTO v_cmd_count, v_match_count, v_exclude_always_match_count + FROM pg_event_trigger_ddl_commands() c; + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0) + THEN + + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'unsupported_command', + v_txid); + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_unsupported_function, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(create_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$ || auto_replication_create_function_name || $BUILD$(); +$BUILD$::TEXT +END AS auto_replication_trigger, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ON sql_drop +WHEN TAG IN('$BUILD$||array_to_string(drop_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$||auto_replication_drop_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_drop_trigger, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(pgl_ddl_deploy.unsupported_tags(),$$','$$)||$BUILD$') +EXECUTE PROCEDURE $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_unsupported_trigger, + +$BUILD$ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs (obj_type, obj_name) AS ( +VALUES +('EVENT TRIGGER','$BUILD$||auto_replication_create_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_drop_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_unsupported_trigger_name||$BUILD$'), +('FUNCTION','$BUILD$||auto_replication_create_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_drop_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_unsupported_function_name||$BUILD$()') +); + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; +DROP EVENT TRIGGER IF EXISTS $BUILD$||auto_replication_create_trigger_name||', '||auto_replication_drop_trigger_name||', '||auto_replication_unsupported_trigger_name||$BUILD$; +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_create_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_drop_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$ + AS undeploy_sql +FROM vars) + +SELECT + b.id, + b.set_name, + b.include_schema_regex, + b.include_only_repset_tables, + b.include_everything, + b.signal_blocking_subscriber_sessions, + b.subscriber_lock_timeout, + b.auto_replication_create_function_name, + b.auto_replication_drop_function_name, + b.auto_replication_unsupported_function_name, + b.auto_replication_create_trigger_name, + b.auto_replication_drop_trigger_name, + b.auto_replication_unsupported_trigger_name, + b.auto_replication_function, + b.auto_replication_drop_function, + b.auto_replication_unsupported_function, + b.auto_replication_trigger, + b.auto_replication_drop_trigger, + b.auto_replication_unsupported_trigger, + b.undeploy_sql, + b.undeploy_sql|| + b.add_queue_table_to_replication||$BUILD$ + $BUILD$||auto_replication_function||$BUILD$ + $BUILD$||auto_replication_drop_function||$BUILD$ + $BUILD$||auto_replication_unsupported_function||$BUILD$ + $BUILD$||auto_replication_trigger||$BUILD$ + $BUILD$||auto_replication_drop_trigger||$BUILD$ + $BUILD$||auto_replication_unsupported_trigger||$BUILD$ + SELECT pgl_ddl_deploy.add_ext_object(obj_type, obj_name) + FROM tmp_objs; + $BUILD$ AS deploy_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ DISABLE; + $BUILD$ AS disable_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ENABLE; + $BUILD$ AS enable_sql, + EXISTS (SELECT 1 + FROM pg_event_trigger + WHERE evtname IN( + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name + ) + AND evtenabled IN('O','R','A') + ) AS is_deployed +FROM build b; + + +/* pgl_ddl_deploy--2.3--2.4.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pgl_ddl_deploy" to load this file. \quit + +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_indexes BOOLEAN NOT NULL DEFAULT FALSE; + + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rewrite_transaction_safe(p_sql text) + RETURNS text + LANGUAGE c + STRICT +AS '$libdir/pgl_ddl_deploy', $function$rewrite_transaction_safe$function$ +; + +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.set_tag_defaults() + RETURNS trigger + LANGUAGE plpgsql +AS $function$ +BEGIN +IF NEW.create_tags IS NULL THEN + NEW.create_tags = CASE WHEN NEW.include_only_repset_tables THEN pgl_ddl_deploy.standard_repset_only_tags() ELSE pgl_ddl_deploy.standard_create_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.create_tags = NEW.create_tags || '{"CREATE INDEX","ALTER INDEX"}'::TEXT[]; + END IF; +END IF; +IF NEW.drop_tags IS NULL THEN + NEW.drop_tags = CASE WHEN NEW.include_only_repset_tables THEN NULL ELSE pgl_ddl_deploy.standard_drop_tags() END; + IF NEW.include_indexes AND NOT NEW.include_only_repset_tables THEN + NEW.drop_tags = NEW.drop_tags || '{"DROP INDEX"}'::TEXT[]; + END IF; +END IF; +RETURN NEW; +END; +$function$ +; + +CREATE OR REPLACE VIEW pgl_ddl_deploy.event_trigger_schema AS +WITH vars AS +(SELECT + sc.id, + set_name, + 'pgl_ddl_deploy.auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_function_name, + 'pgl_ddl_deploy.auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_function_name, + 'auto_rep_ddl_create_'||sc.id::TEXT||'_'||set_name AS auto_replication_create_trigger_name, + 'auto_rep_ddl_drop_'||sc.id::TEXT||'_'||set_name AS auto_replication_drop_trigger_name, + 'auto_rep_ddl_unsupp_'||sc.id::TEXT||'_'||set_name AS auto_replication_unsupported_trigger_name, + include_schema_regex, + include_only_repset_tables, + create_tags, + drop_tags, + ddl_only_replication, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + sc.driver, + + /**** + These constants in DECLARE portion of all functions is identical and can be shared + */ + $BUILD$ + c_search_path TEXT = (SELECT current_setting('search_path')); + c_provider_name TEXT; + --TODO: How do I decide which replication set we care about? + v_pid INT = pg_backend_pid(); + v_rec RECORD; + v_ddl_sql_raw TEXT; + v_ddl_sql_sent TEXT; + v_full_ddl TEXT; + v_sql_tags TEXT[]; + v_cmd_rec RECORD; + v_subcmd_rec RECORD; + v_excluded_subcommands TEXT; + v_contains_any_valid_subcommand INT; + + /***** + We need to strip the DDL of: + 1. Transaction begin and commit, which cannot run inside plpgsql + *****/ + v_txid BIGINT; + v_ddl_length INT; + v_sql TEXT; + v_cmd_count INT; + v_match_count INT; + v_exclude_always_match_count INT; + v_nspname TEXT; + v_relname TEXT; + v_error TEXT; + v_error_detail TEXT; + v_context TEXT; + v_excluded_count INT; + c_exclude_always TEXT = pgl_ddl_deploy.exclude_regex(); + c_exception_msg TEXT = 'Deployment exception logged in pgl_ddl_deploy.exceptions'; + + --Configurable options in function setup + c_set_config_id INT = $BUILD$||sc.id::TEXT||$BUILD$; + -- Even though pglogical supports an array of sets, we only pipe DDL through one at a time + -- So c_set_name is a text not text[] data type. + c_set_name TEXT = '$BUILD$||set_name||$BUILD$'; + c_driver pgl_ddl_deploy.driver = '$BUILD$||sc.driver||$BUILD$'; + c_include_schema_regex TEXT = $BUILD$||COALESCE(''''||include_schema_regex||'''','NULL')||$BUILD$; + c_lock_safe_deployment BOOLEAN = $BUILD$||lock_safe_deployment||$BUILD$; + c_allow_multi_statements BOOLEAN = $BUILD$||allow_multi_statements||$BUILD$; + c_include_only_repset_tables BOOLEAN = $BUILD$||include_only_repset_tables||$BUILD$; + c_include_everything BOOLEAN = $BUILD$||include_everything||$BUILD$; + c_queue_subscriber_failures BOOLEAN = $BUILD$||queue_subscriber_failures||$BUILD$; + c_create_tags TEXT[] = '$BUILD$||create_tags::TEXT||$BUILD$'; + c_blacklisted_tags TEXT[] = '$BUILD$||blacklisted_tags::TEXT||$BUILD$'; + c_exclude_alter_table_subcommands TEXT[] = $BUILD$||COALESCE(quote_literal(exclude_alter_table_subcommands::TEXT),'NULL')||$BUILD$; + c_signal_blocking_subscriber_sessions TEXT = $BUILD$||COALESCE(quote_literal(signal_blocking_subscriber_sessions::TEXT),'NULL')||$BUILD$; + c_subscriber_lock_timeout INT = $BUILD$||COALESCE(subscriber_lock_timeout::TEXT,'NULL')||$BUILD$; + + --Constants based on configuration + c_exec_prefix TEXT =(CASE + WHEN c_lock_safe_deployment + THEN 'SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$' + ELSE '' + END); + c_exec_suffix TEXT = (CASE + WHEN c_lock_safe_deployment + THEN '$PGL_DDL_DEPLOY$);' + ELSE '' + END); + $BUILD$::TEXT AS declare_constants, + + $BUILD$ + --If there are any matches to our replication config, get the query + --This will either be sent, or logged at this point if not deployable + IF (c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0 THEN + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + v_txid = txid_current(); + END IF; + $BUILD$::TEXT AS shared_get_query, +/**** + This is the portion of the event trigger function that evaluates if SQL + is appropriate to propagate, and does propagate the event. It is shared + between the normal and drop event trigger functions. + */ + $BUILD$ + /**** + A multi-statement SQL command may fire this event trigger more than once + This check ensures the SQL is propagated only once, if at all + */ + IF EXISTS + (SELECT 1 FROM pgl_ddl_deploy.events + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + OR EXISTS + (SELECT 1 FROM pgl_ddl_deploy.unhandled + WHERE set_name = c_set_name + AND txid = v_txid + AND ddl_sql_raw = v_ddl_sql_raw + AND pid = v_pid) + THEN + RETURN; + END IF; + + /**** + Get the command tags and reject blacklisted tags + */ + v_sql_tags:=(SELECT pgl_ddl_deploy.sql_command_tags(v_ddl_sql_raw)); + IF (SELECT c_blacklisted_tags && v_sql_tags) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_command_tags', + v_txid); + RETURN; + /**** + If we are not allowing multi-statements at all, reject + */ + ELSEIF (SELECT ARRAY[TG_TAG]::TEXT[] <> v_sql_tags WHERE NOT c_allow_multi_statements) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'rejected_multi_statement', + v_txid); + RETURN; + END IF; + + /**** + If this is an ALTER TABLE statement and we are excluding any subcommand tags, process now. + Note the following. + + Because there can be more than one subcommand, we have a limited ability + to filter out subcommands until such a time as we may have a mechanism for rebuilding only + the SQL we want. In other words, if we have one subcommand that we DO want (i.e. ADD COLUMN) + and one we don't want (i.e. REFERENCES) in the same SQL, and we are "excluding" the latter, + we can't do that exclusion safely because we WANT the ADD COLUMN statement. In such a case, + we are still going to allow the DDL to go through because it's better to break replication than + miss a column addition. + + But if the only subcommand is an excluded one, i.e. ADD CONSTRAINT, then we will indeed ignore + the DDL and the function will RETURN without executing replicate_ddl_command. + */ + IF TG_TAG = 'ALTER TABLE' AND c_exclude_alter_table_subcommands IS NOT NULL THEN + FOR v_cmd_rec IN + SELECT * FROM pg_event_trigger_ddl_commands() + LOOP + IF pgl_ddl_deploy.get_command_type(v_cmd_rec.command) = 'alter table' THEN + WITH subcommands AS ( + SELECT subcommand, + c_exclude_alter_table_subcommands && ARRAY[subcommand] AS subcommand_is_excluded, + MAX(CASE WHEN c_exclude_alter_table_subcommands && ARRAY[subcommand] THEN 0 ELSE 1 END) OVER() AS contains_any_valid_subcommand + FROM unnest(pgl_ddl_deploy.get_altertable_subcmdinfo(v_cmd_rec.command)) AS subcommand + ) + + SELECT (SELECT string_agg(subcommand,', ') FROM subcommands WHERE subcommand_is_excluded), + (SELECT contains_any_valid_subcommand FROM subcommands LIMIT 1) + INTO v_excluded_subcommands, + v_contains_any_valid_subcommand; + IF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 0 THEN + RAISE LOG 'Not processing DDL due to excluded subcommand(s): %: %', v_excluded_subcommands, v_ddl_sql_raw; + RETURN; + ELSEIF v_excluded_subcommands IS NOT NULL AND v_contains_any_valid_subcommand = 1 THEN + RAISE WARNING $INNER_BLOCK$Filtering out more than one subcommand in one ALTER TABLE is not supported. + Allowing to proceed: Rejected: %, SQL: %$INNER_BLOCK$, v_excluded_subcommands, v_ddl_sql_raw; + END IF; + END IF; + END LOOP; + END IF; + + SELECT pgl_ddl_deploy.rewrite_transaction_safe(v_ddl_sql_raw) INTO v_ddl_sql_sent; + + --Get provider name, in order only to run command on a subscriber to this provider + c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); + + /* + Build replication DDL command which will conditionally run only on the subscriber + In other words, this MUST be a no-op on the provider + **Because the DDL has already run at this point (ddl_command_end)** + */ + v_full_ddl:=$INNER_BLOCK$ + --Be sure to use provider's search_path for SQL environment consistency + SET SEARCH_PATH TO $INNER_BLOCK$|| + CASE WHEN COALESCE(c_search_path,'') IN('','""') THEN quote_literal('') ELSE c_search_path END||$INNER_BLOCK$; + + $INNER_BLOCK$||c_exec_prefix||v_ddl_sql_sent||c_exec_suffix||$INNER_BLOCK$ + ; + $INNER_BLOCK$; + RAISE DEBUG 'v_full_ddl: %', v_full_ddl; + RAISE DEBUG 'c_set_config_id: %', c_set_config_id; + RAISE DEBUG 'c_set_name: %', c_set_name; + RAISE DEBUG 'c_driver: %', c_driver; + RAISE DEBUG 'v_ddl_sql_sent: %', v_ddl_sql_sent; + + v_sql:=$INNER_BLOCK$ + SELECT $BUILD$||CASE + WHEN sc.driver = 'native' + THEN 'pgl_ddl_deploy' + WHEN sc.driver = 'pglogical' + THEN 'pglogical' + ELSE 'ERROR-EXCEPTION' END||$BUILD$.replicate_ddl_command($REPLICATE_DDL_COMMAND$ + SELECT pgl_ddl_deploy.subscriber_command + ( + p_provider_name := $INNER_BLOCK$||COALESCE(quote_literal(c_provider_name), 'NULL')||$INNER_BLOCK$, + p_set_name := ARRAY[$INNER_BLOCK$||quote_literal(c_set_name)||$INNER_BLOCK$], + p_nspname := $INNER_BLOCK$||COALESCE(quote_literal(v_nspname), 'NULL')::TEXT||$INNER_BLOCK$, + p_relname := $INNER_BLOCK$||COALESCE(quote_literal(v_relname), 'NULL')::TEXT||$INNER_BLOCK$, + p_ddl_sql_sent := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_ddl_sql_sent||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_full_ddl := $pgl_ddl_deploy_sql$$INNER_BLOCK$||v_full_ddl||$INNER_BLOCK$$pgl_ddl_deploy_sql$, + p_pid := $INNER_BLOCK$||v_pid::TEXT||$INNER_BLOCK$, + p_set_config_id := $INNER_BLOCK$||c_set_config_id::TEXT||$INNER_BLOCK$, + p_queue_subscriber_failures := $INNER_BLOCK$||c_queue_subscriber_failures||$INNER_BLOCK$, + p_signal_blocking_subscriber_sessions := $INNER_BLOCK$||COALESCE(quote_literal(c_signal_blocking_subscriber_sessions),'NULL')||$INNER_BLOCK$, + p_lock_timeout := $INNER_BLOCK$||COALESCE(c_subscriber_lock_timeout, 3000)||$INNER_BLOCK$, + p_driver := $INNER_BLOCK$||quote_literal(c_driver)||$INNER_BLOCK$ + ); + $REPLICATE_DDL_COMMAND$, + --Pipe this DDL command through chosen replication set + ARRAY['$INNER_BLOCK$||c_set_name||$INNER_BLOCK$']); + $INNER_BLOCK$; + + RAISE DEBUG 'v_sql: %', v_sql; + EXECUTE v_sql; + + INSERT INTO pgl_ddl_deploy.events + (set_config_id, + set_name, + pid, + executed_at, + ddl_sql_raw, + ddl_sql_sent, + txid) + VALUES + (c_set_config_id, + c_set_name, + v_pid, + current_timestamp, + v_ddl_sql_raw, + v_ddl_sql_sent, + v_txid); + $BUILD$::TEXT AS shared_deploy_logic, + $BUILD$ + ELSEIF (v_match_count > 0 AND v_cmd_count <> v_match_count) THEN + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'mixed_objects', + v_txid); + $BUILD$::TEXT AS shared_mixed_obj_logic, + $BUILD$ + -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + $BUILD$::TEXT AS dropped_objects_query, + + $BUILD$ + /** + Catch any exceptions and log in a local table + As a safeguard, if even the exception handler fails, exit cleanly but add a server log message + **/ + EXCEPTION WHEN OTHERS THEN + GET STACKED DIAGNOSTICS + v_context = PG_EXCEPTION_CONTEXT, + v_error = MESSAGE_TEXT, + v_error_detail = PG_EXCEPTION_DETAIL; + BEGIN + INSERT INTO pgl_ddl_deploy.exceptions (set_config_id, set_name, pid, executed_at, ddl_sql, err_msg, err_state) + VALUES (c_set_config_id, c_set_name, v_pid, current_timestamp, v_sql, format('%s %s %s', v_error, v_context, v_error_detail), SQLSTATE); + RAISE WARNING '% (%: % - %)', c_exception_msg, v_error, v_context, v_error_detail; + --No matter what, don't let this function block any DDL + EXCEPTION WHEN OTHERS THEN + RAISE WARNING 'Unhandled exception % %', SQLERRM, SQLSTATE; + END; + $BUILD$::TEXT AS shared_exception_handler, + + $BUILD$ + FROM pg_namespace n + INNER JOIN pg_class c ON n.oid = c.relnamespace + AND c.relpersistence = 'p' + WHERE n.nspname ~* c_include_schema_regex + AND n.nspname !~* c_exclude_always + AND EXISTS (SELECT 1 + FROM pg_index i + WHERE i.indrelid = c.oid + AND i.indisprimary) + AND NOT EXISTS + (SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.name = c_set_name + AND rsr.relid = c.oid + AND rsr.driver = c_driver) + $BUILD$::TEXT AS shared_repl_set_tables, + + $BUILD$ + SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name ~* c_include_schema_regex + AND schema_name !~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_include_schema_regex + AND object_identity !~* c_exclude_always) + ) + ) + OR + --include_only_repset_tables usage: + ( + ($BUILD$||include_only_repset_tables||$BUILD$) AND + (EXISTS + ( + SELECT 1 + FROM pgl_ddl_deploy.rep_set_table_wrapper() rsr + WHERE rsr.relid = c.objid + AND c.object_type in('table','table column','table constraint') + AND rsr.name = '$BUILD$||sc.set_name||$BUILD$' + AND rsr.driver = '$BUILD$||sc.driver||$BUILD$' + ) + ) + ) + THEN 1 + ELSE 0 END) AS match_count, + SUM(CASE + WHEN + --include_everything usage still excludes exclude_always regex: + ( + ($BUILD$||include_everything||$BUILD$) AND + ( + (schema_name ~* c_exclude_always) + OR + (object_type = 'schema' + AND object_identity ~* c_exclude_always) + ) + ) + THEN 1 + ELSE 0 END) AS exclude_always_match_count + $BUILD$::TEXT AS shared_match_count +FROM pgl_ddl_deploy.rep_set_wrapper() rs +INNER JOIN pgl_ddl_deploy.set_configs sc ON sc.set_name = rs.name AND sc.driver = rs.driver +) + +, build AS ( +SELECT + id, + set_name, + include_schema_regex, + include_only_repset_tables, + include_everything, + signal_blocking_subscriber_sessions, + subscriber_lock_timeout, + auto_replication_create_function_name, + auto_replication_drop_function_name, + auto_replication_unsupported_function_name, + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name, + +CASE WHEN driver = 'pglogical' THEN '--no-op pglogical diver'::TEXT +WHEN driver = 'native' THEN $BUILD$ +DO $$ +BEGIN + +IF NOT EXISTS (SELECT 1 +FROM pg_publication_tables +WHERE pubname = '$BUILD$||set_name||$BUILD$' +AND schemaname = 'pgl_ddl_deploy' +AND tablename = 'queue') THEN + ALTER PUBLICATION $BUILD$||quote_ident(set_name)||$BUILD$ + ADD TABLE pgl_ddl_deploy.queue; +END IF; + +END$$; +$BUILD$ +END AS add_queue_table_to_replication, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$ || auto_replication_create_function_name || $BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , MAX(c.schema_name) + , MAX(cl.relname) + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_nspname, v_relname + FROM pg_event_trigger_ddl_commands() c + LEFT JOIN LATERAL + (SELECT cl.relname + FROM pg_class cl + WHERE cl.oid = c.objid + AND c.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') + -- There should only be one table modified per event trigger + -- At least that's the best we will do now + LIMIT 1) cl ON TRUE; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_cmd_count = v_match_count)) + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension + FROM pg_event_trigger_ddl_commands(); + + /** + Add table to replication set immediately, if required, and only if the set_config includes CREATE TABLE. + We do not filter to tags here, because of possibility of multi-statement SQL. + Optional ddl_only_replication will never auto-add tables to replication because the + purpose is to only replicate keep the structure synchronized on the subscriber with no data. + **/ + IF c_create_tags && '{"CREATE TABLE"}' AND NOT $BUILD$||include_only_repset_tables||$BUILD$ AND NOT $BUILD$||ddl_only_replication||$BUILD$ THEN + PERFORM pgl_ddl_deploy.add_table_to_replication( + p_driver:=c_driver + ,p_set_name:=c_set_name + ,p_relation:=c.oid + ,p_synchronize_data:=false + ) + $BUILD$||shared_repl_set_tables||$BUILD$; + END IF; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$::TEXT +END AS auto_replication_function, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_drop_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + , SUM(CASE + WHEN + --include_schema_regex usage: + ( + (NOT $BUILD$||include_only_repset_tables||$BUILD$) AND + ( + (schema_name !~* '^(pg_catalog|pg_toast)$' + AND schema_name !~* c_include_schema_regex) + OR (object_type = 'schema' + AND object_identity !~* '^(pg_catalog|pg_toast)$' + AND object_identity !~* c_include_schema_regex) + ) + ) + --include_only_repset_tables cannot be used with DROP because + --the objects no longer exist to be checked: + THEN 1 + ELSE 0 END) AS excluded_count + INTO v_cmd_count, v_match_count, v_exclude_always_match_count, v_excluded_count + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_get_query||$BUILD$ + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR (v_match_count > 0 AND v_excluded_count = 0)) + + THEN + + $BUILD$||shared_deploy_logic||$BUILD$ + + INSERT INTO pgl_ddl_deploy.commands + (set_config_id, + set_name, + pid, + txid, + classid, + objid, + objsubid, + command_tag, + object_type, + schema_name, + object_identity, + in_extension) + SELECT c_set_config_id, + c_set_name, + v_pid, + v_txid, + classid, + objid, + objsubid, + TG_TAG, + object_type, + schema_name, + object_identity, + NULL + FROM $BUILD$||dropped_objects_query||$BUILD$ as c; + + $BUILD$||shared_mixed_obj_logic||$BUILD$ + + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_drop_function, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE OR REPLACE FUNCTION $BUILD$||auto_replication_unsupported_function_name||$BUILD$() RETURNS EVENT_TRIGGER +AS +$BODY$ +DECLARE + $BUILD$||declare_constants||$BUILD$ +BEGIN + + /***** + Only enter execution body if object being altered is relevant + */ + SELECT COUNT(1) + , $BUILD$||shared_match_count||$BUILD$ + INTO v_cmd_count, v_match_count, v_exclude_always_match_count + FROM pg_event_trigger_ddl_commands() c; + + IF ((c_include_everything AND v_exclude_always_match_count = 0) OR v_match_count > 0) + THEN + + v_ddl_sql_raw = pgl_ddl_deploy.current_query(); + + PERFORM pgl_ddl_deploy.log_unhandled( + c_set_config_id, + c_set_name, + v_pid, + v_ddl_sql_raw, + TG_TAG, + 'unsupported_command', + v_txid); + END IF; + +$BUILD$||shared_exception_handler||$BUILD$ +END; +$BODY$ +LANGUAGE plpgsql; +$BUILD$ +END + AS auto_replication_unsupported_function, + +CASE WHEN create_tags IS NULL THEN '--no-op-null-create-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(create_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$ || auto_replication_create_function_name || $BUILD$(); +$BUILD$::TEXT +END AS auto_replication_trigger, + +CASE WHEN drop_tags IS NULL THEN '--no-op-null-drop-tags'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ON sql_drop +WHEN TAG IN('$BUILD$||array_to_string(drop_tags,$$','$$)||$BUILD$') +--TODO - CREATE INDEX HANDLING +EXECUTE PROCEDURE $BUILD$||auto_replication_drop_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_drop_trigger, + +CASE WHEN include_only_repset_tables THEN '--no-op-only-repset-tables'::TEXT ELSE +$BUILD$ +CREATE EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ON ddl_command_end +WHEN TAG IN('$BUILD$||array_to_string(pgl_ddl_deploy.unsupported_tags(),$$','$$)||$BUILD$') +EXECUTE PROCEDURE $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$::TEXT +END AS auto_replication_unsupported_trigger, + +$BUILD$ +DROP TABLE IF EXISTS tmp_objs; +CREATE TEMP TABLE tmp_objs (obj_type, obj_name) AS ( +VALUES +('EVENT TRIGGER','$BUILD$||auto_replication_create_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_drop_trigger_name||$BUILD$'), +('EVENT TRIGGER','$BUILD$||auto_replication_unsupported_trigger_name||$BUILD$'), +('FUNCTION','$BUILD$||auto_replication_create_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_drop_function_name||$BUILD$()'), +('FUNCTION','$BUILD$||auto_replication_unsupported_function_name||$BUILD$()') +); + +SELECT pgl_ddl_deploy.drop_ext_object(obj_type, obj_name) +FROM tmp_objs; +DROP EVENT TRIGGER IF EXISTS $BUILD$||auto_replication_create_trigger_name||', '||auto_replication_drop_trigger_name||', '||auto_replication_unsupported_trigger_name||$BUILD$; +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_create_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_drop_function_name||$BUILD$(); +DROP FUNCTION IF EXISTS $BUILD$||auto_replication_unsupported_function_name||$BUILD$(); +$BUILD$ + AS undeploy_sql +FROM vars) + +SELECT + b.id, + b.set_name, + b.include_schema_regex, + b.include_only_repset_tables, + b.include_everything, + b.signal_blocking_subscriber_sessions, + b.subscriber_lock_timeout, + b.auto_replication_create_function_name, + b.auto_replication_drop_function_name, + b.auto_replication_unsupported_function_name, + b.auto_replication_create_trigger_name, + b.auto_replication_drop_trigger_name, + b.auto_replication_unsupported_trigger_name, + b.auto_replication_function, + b.auto_replication_drop_function, + b.auto_replication_unsupported_function, + b.auto_replication_trigger, + b.auto_replication_drop_trigger, + b.auto_replication_unsupported_trigger, + b.undeploy_sql, + b.undeploy_sql|| + b.add_queue_table_to_replication||$BUILD$ + $BUILD$||auto_replication_function||$BUILD$ + $BUILD$||auto_replication_drop_function||$BUILD$ + $BUILD$||auto_replication_unsupported_function||$BUILD$ + $BUILD$||auto_replication_trigger||$BUILD$ + $BUILD$||auto_replication_drop_trigger||$BUILD$ + $BUILD$||auto_replication_unsupported_trigger||$BUILD$ + SELECT pgl_ddl_deploy.add_ext_object(obj_type, obj_name) + FROM tmp_objs; + $BUILD$ AS deploy_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ DISABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ DISABLE; + $BUILD$ AS disable_sql, + $BUILD$ + ALTER EVENT TRIGGER $BUILD$||auto_replication_create_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_drop_trigger_name||$BUILD$ ENABLE; + ALTER EVENT TRIGGER $BUILD$||auto_replication_unsupported_trigger_name||$BUILD$ ENABLE; + $BUILD$ AS enable_sql, + EXISTS (SELECT 1 + FROM pg_event_trigger + WHERE evtname IN( + auto_replication_create_trigger_name, + auto_replication_drop_trigger_name, + auto_replication_unsupported_trigger_name + ) + AND evtenabled IN('O','R','A') + ) AS is_deployed +FROM build b; + + diff --git a/pgl_ddl_deploy-sql-maker.sh b/pgl_ddl_deploy-sql-maker.sh index 4e3d02a..1ec4778 100755 --- a/pgl_ddl_deploy-sql-maker.sh +++ b/pgl_ddl_deploy-sql-maker.sh @@ -2,8 +2,8 @@ set -eu -last_version=2.2 -new_version=2.3 +last_version=2.3 +new_version=2.4 last_version_file=pgl_ddl_deploy--${last_version}.sql new_version_file=pgl_ddl_deploy--${new_version}.sql update_file=pgl_ddl_deploy--${last_version}--${new_version}.sql @@ -36,6 +36,9 @@ d=$2 create_update_file_with_header # Add view and function changes +add_file schema/2.4.sql $update_file +add_file functions/rewrite_transaction_safe.sql $update_file +add_file functions/set_tag_defaults.sql $update_file add_file views/event_trigger_schema.sql $update_file # Only copy diff and new files after last version, and add the update script diff --git a/pgl_ddl_deploy.c b/pgl_ddl_deploy.c index ca2b52a..72c7e4b 100644 --- a/pgl_ddl_deploy.c +++ b/pgl_ddl_deploy.c @@ -4,11 +4,15 @@ #include "tcop/utility.h" #include "utils/builtins.h" #include "parser/parser.h" +#include "nodes/nodes.h" +#include "utils/ruleutils.h" +#include "postgres_deparse.h" PG_MODULE_MAGIC; PG_FUNCTION_INFO_V1(pgl_ddl_deploy_current_query); PG_FUNCTION_INFO_V1(sql_command_tags); +PG_FUNCTION_INFO_V1(rewrite_transaction_safe); /* Our own version of debug_query_string - see below */ const char *pgl_ddl_deploy_debug_query_string; @@ -84,3 +88,54 @@ sql_command_tags(PG_FUNCTION_ARGS) PG_RETURN_ARRAYTYPE_P(DatumGetPointer(makeArrayResult(astate, CurrentMemoryContext))); } +Datum +rewrite_transaction_safe(PG_FUNCTION_ARGS) +{ + + text *sql_t = PG_GETARG_TEXT_P(0); + char *sql; + List *parsetree_list; + ListCell *parsetree_item; + StringInfoData str; + text *result; + initStringInfo(&str); + + /* + * Get the SQL parsetree + */ + sql = text_to_cstring(sql_t); + parsetree_list = pg_parse_query(sql); + + /* + * Iterate through each parsetree_item to get CommandTag + */ + foreach(parsetree_item, parsetree_list) + { + RawStmt *parsetree = (RawStmt *) lfirst(parsetree_item); + bool shouldEmit = true; + if(IsA(parsetree->stmt, TransactionStmt)) { + TransactionStmtKind kind = ((TransactionStmt *) parsetree->stmt)->kind; + shouldEmit = kind != TRANS_STMT_BEGIN && kind != TRANS_STMT_START && kind != TRANS_STMT_COMMIT; + } + if(IsA(parsetree->stmt, IndexStmt)) { + IndexStmt *indexStmt = (IndexStmt *) parsetree->stmt; + indexStmt->concurrent = false; + } + if(IsA(parsetree->stmt, DropStmt)) { + DropStmt *dropStmt = (DropStmt *) parsetree->stmt; + dropStmt->concurrent = false; + } + if(shouldEmit) { + deparseRawStmt(&str, parsetree); + appendStringInfoChar(&str, ';'); + if(foreach_current_index(parsetree_item) < list_length(parsetree_list) - 1) + { + appendStringInfoChar(&str, ' '); + } + } + } + result = cstring_to_text(str.data); + pfree(str.data); + PG_RETURN_TEXT_P(result); +} + diff --git a/pgl_ddl_deploy.control b/pgl_ddl_deploy.control index e68a0e3..4f1f1ef 100644 --- a/pgl_ddl_deploy.control +++ b/pgl_ddl_deploy.control @@ -1,5 +1,5 @@ # pgl_ddl_deploy extension comment = 'automated ddl deployment using pglogical' module_pathname = '$libdir/pgl_ddl_deploy' -default_version = '2.3' +default_version = '2.4' schema = 'pgl_ddl_deploy' diff --git a/postgres_deparse.c b/postgres_deparse.c new file mode 100644 index 0000000..fe8566b --- /dev/null +++ b/postgres_deparse.c @@ -0,0 +1,12253 @@ +// From https://github.com/pganalyze/libpg_query/tree/156705b347d347c154fdfddf9341c07a9fa73dc2 + +// Copyright (c) 2015, Lukas Fittl +// Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres_deparse.h" + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +/* + * # Deparser overview + * + * The deparser works by walking the input parse tree and emitting into the + * currently active "part" as pointed to (indirectly) by the state struct. + * + * A lot of the structure of the deparser described below is meant to support + * the optional "pretty print" mode that can be enabled and configured through + * the deparser options, and inserts whitespace (newlines/spaces) as needed to + * make the output easier to read. + * + * ## Nesting levels + * + * Starting at the state struct we have a currently active "nesting level", + * which indicates the base indentation, as well as contains one or more part + * groups, each of which has one or more parts. + * + * Nesting levels are typically opened, or "increased", when processing a new + * statement contained within other statements, or for certain statement-like + * constructs (e.g. CASE clauses) that require custom indendation. + * + * Nesting levels are closed, or "decreased", when exiting such statements or + * statement-like constructs. During this operation all parts and subparts get + * flattened (turned into a simple list of parts), and are added to the parent + * nesting level. + * + * At the end of the tree walk the parts of the top most nesting level get + * emitted into the output string, formatted based on the deparse options. + * + * ## Part groups + * + * Part groups are usually started for each "major" keyword, which is chosen + * for how the output is intended to be laid out. For example, the "FROM" + * keyword in a SELECT statement is considered "major" and starts a new part + * group, vs the "JOIN" keyword is not, and as such both regular tables and + * JOIN clauses will be within one part group. + * + * ## Parts, indentation and merging + * + * The parts contained in part groups may be indented one additional level + * beyond the base indentation of the currently active nesting level, to help + * differentiate them from the major keywords. This can be turned off with + * DEPARSE_PART_NO_INDENT, for example as needed to format WITH clauses + * effectively. + * + * Parts may be merged with other parts within the same group, if the indent + * mode is set to DEPARSE_PART_INDENT_AND_MERGE. This is utilized to put + * certain items, for example the target list items in SELECT on one or more + * lines, breaking at separators as needed to respect the maximum line limit. + * + * ## Node context + * + * Node context is used when the same function in the deparser needs to behave + * differently depending on the parent node. For example, a SELECT statement + * needs wrapping parenthesis in certain situations where the parent statement + * uses a set operation (e.g. UNION). + * + * ## Comments + * + * Comments do not exist as nodes in a Postgres parse tree, and as such need to + * be passed in separately through the deparser options. They are placed in the + * output on a best effort basis, by matching against node locations. Comments + * will only be output at most once, but may not be output at all in certain + * cases, for example when the comment's specified match location is never + * reached by any of the nodes visited. + */ + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_SELECT, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_DOMAIN, + DEPARSE_NODE_CONTEXT_SET_STATEMENT, + DEPARSE_NODE_CONTEXT_FUNC_EXPR, + DEPARSE_NODE_CONTEXT_SELECT_SETOP, + DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +typedef enum DeparsePartIndentMode { + /* Don't indent parts at all, used in special cases (e.g. WITH clauses) */ + DEPARSE_PART_NO_INDENT, + + /* Indent parts but don't merge them (keep each on their own line) */ + DEPARSE_PART_INDENT, + + /* Indent parts and merge them together up to the max line length */ + DEPARSE_PART_INDENT_AND_MERGE +} DeparsePartIndentMode; + +// Each part is typically one line to be emitted in pretty print mode +typedef struct DeparseStatePart +{ + StringInfo str; + + /* If this gets emitted as its own line, number of spaces to be added as indentation */ + int indent; + + /* Allow merging this part with adjacent parts that are marked as mergeable */ + bool mergeable; +} DeparseStatePart; + +// A part group are typically all parts associated with a major keyword +typedef struct DeparseStatePartGroup +{ + const char *keyword; + List *parts; + DeparsePartIndentMode indent_mode; +} DeparseStatePartGroup; + +// Nesting levels may be statements, or complex parts of statements that should be indented (e.g. CASE) +typedef struct DeparseStateNestingLevel +{ + /* List of DeparseStatePartGroup items */ + List *part_groups; + + /* Add this much indentation to every part */ + int base_indent; +} DeparseStateNestingLevel; + +typedef struct DeparseState +{ + DeparseStateNestingLevel *current; + + /* List of DeparseStatePart items */ + List *result_parts; + + /* Deparse options originally passed in */ + PostgresDeparseOpts *opts; + + /* Set of indexes of comments already placed in the output query */ + Bitmapset *emitted_comments; +} DeparseState; + +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context); +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause); +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(DeparseState *state, ResTarget *res_target, DeparseNodeContext context); +static void deparseAlias(DeparseState *state, Alias *alias); +static void deparseWindowDef(DeparseState *state, WindowDef* window_def); +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref); +static void deparseSubLink(DeparseState *state, SubLink* sub_link); +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr); +static void deparseAStar(DeparseState *state, A_Star* a_star); +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause); +static void deparseSortBy(DeparseState *state, SortBy* sort_by); +static void deparseParamRef(DeparseState *state, ParamRef* param_ref); +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function); +static void deparseWithClause(DeparseState *state, WithClause *with_clause); +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr); +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte); +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect); +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func); +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr * array_expr); +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr); +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(DeparseState *state, TypeName *type_name); +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name); +static void deparseNullTest(DeparseState *state, NullTest *null_test); +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr); +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when); +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection); +static void deparseAIndices(DeparseState *state, A_Indices *a_indices); +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test); +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def); +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt); +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem); +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt); +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt); +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause); +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default); +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter); +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec); +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt); +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func); +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set); +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context); +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context); +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize); +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *json_is_predicate); +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg); +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg); +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor); +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor); +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor); +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr); +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output); +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr); +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr); +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr); +static void deparseJsonTable(DeparseState *state, JsonTable *json_table); +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column); +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns); +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec); +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior); +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr); +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes); +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseConstraint(DeparseState *state, Constraint *constraint, DeparseNodeContext context); +static void deparseATAlterConstraint(DeparseState *state, ATAlterConstraint *constraint); +static void deparseSchemaStmt(DeparseState *state, Node *node); +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item); +static void deparseAConst(DeparseState *state, A_Const *a_const); +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(DeparseState *state, Node *node); +static void deparseRuleActionStmt(DeparseState *state, Node *node); +static void deparseExplainableStmt(DeparseState *state, Node *node); +static void deparseStmt(DeparseState *state, Node *node); +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context); + +static void +removeTrailingSpaceFromStr(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static DeparseStatePart * +makeDeparseStatePart(DeparseState *state, DeparseStateNestingLevel *level, DeparsePartIndentMode indent_mode) +{ + DeparseStatePart *part = palloc(sizeof(DeparseStatePart)); + part->str = makeStringInfo(); + part->indent = level->base_indent; + if (indent_mode != DEPARSE_PART_NO_INDENT) + part->indent += state->opts->indent_size; + part->mergeable = indent_mode == DEPARSE_PART_INDENT_AND_MERGE; + return part; +} + +static void +freeDeparseStatePart(DeparseStatePart *part) +{ + pfree(part->str->data); + pfree(part->str); + pfree(part); +} + +// Returns current active part group, and initializes the first one (including an empty part) if needed +static DeparseStatePartGroup * +deparseGetCurrentPartGroup(DeparseState *state) +{ + DeparseStateNestingLevel *level = state->current; + if (level->part_groups) + return (DeparseStatePartGroup *) llast(level->part_groups); + + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, level, part_group->indent_mode)); + level->part_groups = lappend(level->part_groups, part_group); + return part_group; +} + +static DeparseStatePart * +deparseGetCurrentPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + return (DeparseStatePart *) llast(part_group->parts); +} + +static void +deparseMarkCurrentPartNonMergable(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + part->mergeable = false; +} + +static StringInfo deparseGetCurrentStringInfo(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + Assert(part != NULL); + return part->str; +} + +static void deparseAppendStringInfo(DeparseState *state, const char *fmt,...) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + int save_errno = errno; + + for (;;) + { + va_list args; + int needed; + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + needed = appendStringInfoVA(str, fmt, args); + va_end(args); + + if (needed == 0) + break; /* success */ + + /* Increase the buffer size and try again. */ + enlargeStringInfo(str, needed); + } +} + +static void deparseAppendStringInfoString(DeparseState *state, const char *s) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoString(str, s); +} + +static void deparseAppendStringInfoChar(DeparseState *state, char ch) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoChar(str, ch); +} + +static void +removeTrailingSpace(DeparseState *state) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + removeTrailingSpaceFromStr(str); +} + +static void +deparseRemoveTrailingEmptyPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + DeparseStatePart *last_part = deparseGetCurrentPart(state); + + if (last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + part_group->parts = list_delete_last(part_group->parts); + } +} + +static void +deparseAppendPart(DeparseState *state, bool deduplicate) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + + // Remove previous part if its empty and we deduplicate. We don't keep + // the existing part since it may have the wrong indent level or mode. + if (deduplicate) + deparseRemoveTrailingEmptyPart(state); + + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, part_group->indent_mode)); +} + +static void +deparseAppendCommaAndPart(DeparseState *state) +{ + if (state->opts->commas_start_of_line) + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, ", "); + } + else + { + deparseAppendStringInfoChar(state, ','); + deparseAppendPart(state, true); + } +} + +static void +deparseAppendPartGroup(DeparseState *state, const char *keyword, DeparsePartIndentMode indent_mode) +{ + DeparseStateNestingLevel *level = state->current; + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + + if (list_length(level->part_groups) > 0) + removeTrailingSpace(state); + + part_group->keyword = keyword; + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, indent_mode)); + part_group->indent_mode = indent_mode; + + level->part_groups = lappend(level->part_groups, part_group); +} + +static void +deparseAppendCommentsIfNeeded(DeparseState *state, ParseLoc location) +{ + for (int i = 0; i < state->opts->comment_count; i++) + { + if (bms_is_member(i, state->emitted_comments)) + continue; + + PostgresDeparseComment *comment = state->opts->comments[i]; + if (comment->match_location > location) + continue; + + // Emit one less leading newline if we already emitted one for formatting reasons + int newlines_before_comment = comment->newlines_before_comment; + if (state->opts->pretty_print && newlines_before_comment > 0 && + deparseGetCurrentPartGroup(state)->keyword != NULL && + deparseGetCurrentStringInfo(state)->len == 0) + newlines_before_comment -= 1; + + for (int j = 0; j < newlines_before_comment; j++) + { + if (state->opts->pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + deparseAppendStringInfoString(state, comment->str); + + /* never merge comments with other parts */ + deparseMarkCurrentPartNonMergable(state); + + for (int j = 0; j < comment->newlines_after_comment; j++) + { + if (state->opts->pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + state->emitted_comments = bms_add_member(state->emitted_comments, i); + } +} + +static void +deparseEmit(DeparseState *state, StringInfo str) +{ + ListCell *lc; + + /* If the last part is empty, drop it, so we don't confuse the newline output */ + DeparseStatePart *last_part = (DeparseStatePart *) llast(state->result_parts); + if (last_part && last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + state->result_parts = list_delete_last(state->result_parts); + } + + foreach (lc, state->result_parts) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc); + bool last_part = list_cell_number(state->result_parts, lc) == list_length(state->result_parts) - 1; + + if (!state->opts->pretty_print && part->str->len > 0 && (part->str->data[0] == ')' || part->str->data[0] == ';')) + removeTrailingSpaceFromStr(str); + + if (state->opts->pretty_print) + { + for (int i = 0; i < part->indent; i++) + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, part->str->data); + removeTrailingSpaceFromStr(str); + + if (!last_part) + { + if (state->opts->pretty_print) + appendStringInfoChar(str, '\n'); + else if (str->data[str->len - 1] != '(') + appendStringInfoChar(str, ' '); + } + + freeDeparseStatePart(part); + } + list_free(state->result_parts); + state->result_parts = NIL; + + if (state->opts->pretty_print && state->opts->trailing_newline) + appendStringInfoChar(str, '\n'); +} + +static DeparseStateNestingLevel * +deparseStateIncreaseNestingLevel(DeparseState *state) +{ + DeparseStateNestingLevel *parent = state->current; + DeparseStateNestingLevel *level = palloc0(sizeof(DeparseStateNestingLevel)); + if (parent) + { + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + level->base_indent = parent->base_indent + state->opts->indent_size; + if (part_group->indent_mode != DEPARSE_PART_NO_INDENT) /* Indent again if parts next to us are also indented */ + level->base_indent += state->opts->indent_size; + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } + state->current = level; + return parent; +} + +static void +deparseStateDecreaseNestingLevel(DeparseState *state, DeparseStateNestingLevel *parent_level) +{ + ListCell *lc; + ListCell *lc2; + DeparseStateNestingLevel *level = state->current; + Assert(level != NULL); + + foreach (lc, level->part_groups) + { + DeparseStatePartGroup *part_group = (DeparseStatePartGroup *) lfirst(lc); + + /* Merge parts */ + if (part_group->indent_mode == DEPARSE_PART_INDENT_AND_MERGE && list_length(part_group->parts) > 1) + { + DeparseStatePart *target = (DeparseStatePart *) linitial(part_group->parts); + for_each_from (lc2, part_group->parts, 1) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc2); + removeTrailingSpaceFromStr(target->str); + if (target->mergeable && part->mergeable && + target->indent + target->str->len + 1 + part->str->len <= state->opts->max_line_length) + { + if (target->str->len > 0 && target->str->data[target->str->len - 1] != '(') + appendStringInfoChar(target->str, ' '); + appendStringInfoString(target->str, part->str->data); + freeDeparseStatePart(part); + part_group->parts = foreach_delete_current(part_group->parts, lc2); + } + else + { + target = part; + } + } + } + + if (part_group->keyword != NULL) + { + DeparseStatePart *target = makeDeparseStatePart(state, level, false); + appendStringInfoString(target->str, part_group->keyword); + part_group->parts = list_insert_nth(part_group->parts, 0, target); + + if (list_length(part_group->parts) == 2 || part_group->indent_mode == DEPARSE_PART_NO_INDENT) + { + DeparseStatePart *part = (DeparseStatePart *) lsecond(part_group->parts); + if (part->str->len > 0) + appendStringInfo(target->str, " %s", part->str->data); + freeDeparseStatePart(part); + part_group->parts = list_delete_nth_cell(part_group->parts, 1); + } + } + + if (parent_level) + { + DeparseStatePartGroup *parent_part_group = (DeparseStatePartGroup *) llast(parent_level->part_groups); + parent_part_group->parts = list_concat(parent_part_group->parts, part_group->parts); + } + else + { + // If its the top level, save as results instead + state->result_parts = list_concat(state->result_parts, part_group->parts); + } + + list_free(part_group->parts); + pfree(part_group); + } + list_free(level->part_groups); + pfree(level); + + state->current = parent_level; + + if (parent_level) + { + /* Make sure parent statement writes that follow are on their own line */ + deparseAppendPart(state, true); + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies, and modified to work with deparser + * state. + */ +static void +deparseStringLiteral(DeparseState *state, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + deparseAppendStringInfoChar(state, ESCAPE_STRING_SYNTAX); + deparseAppendStringInfoChar(state, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + deparseAppendStringInfoChar(state, ch); + deparseAppendStringInfoChar(state, ch); + } + deparseAppendStringInfoChar(state, '\''); +} + +// "any_name" in gram.y +static void deparseAnyName(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} +static void deparseAnyNameSkipFirst(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} +static void deparseAnyNameSkipLast(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + deparseAppendStringInfoChar(state, '.'); + } + } +} + +// "func_expr" in gram.y +static void deparseFuncExpr(DeparseState *state, Node *node, DeparseNodeContext context) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(state, castNode(FuncCall, node), context); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(state, castNode(XmlExpr, node), context); + break; + case T_XmlSerialize: + deparseXmlSerialize(state, castNode(XmlSerialize, node)); + break; + case T_JsonObjectAgg: + deparseJsonObjectAgg(state, castNode(JsonObjectAgg, node)); + break; + case T_JsonArrayAgg: + deparseJsonArrayAgg(state, castNode(JsonArrayAgg, node)); + break; + case T_JsonObjectConstructor: + deparseJsonObjectConstructor(state, castNode(JsonObjectConstructor, node)); + break; + case T_JsonArrayConstructor: + deparseJsonArrayConstructor(state, castNode(JsonArrayConstructor, node)); + break; + case T_JsonArrayQueryConstructor: + deparseJsonArrayQueryConstructor(state, castNode(JsonArrayQueryConstructor, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in func_expr: %d", + (int) nodeTag(node)); + break; + } +} + +static void deparseCExpr(DeparseState *state, Node *node); + +// "a_expr" in gram.y +static void deparseExpr(DeparseState *state, Node *node, DeparseNodeContext context) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_ColumnRef: + case T_A_Const: + case T_ParamRef: + case T_A_Indirection: + case T_CaseExpr: + case T_SubLink: + case T_A_ArrayExpr: + case T_RowExpr: + case T_GroupingFunc: + deparseCExpr(state, node); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CollateClause: + deparseCollateClause(state, castNode(CollateClause, node)); + break; + case T_A_Expr: + deparseAExpr(state, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_A_EXPR); + break; + case T_BoolExpr: + deparseBoolExpr(state, castNode(BoolExpr, node)); + break; + case T_NullTest: + deparseNullTest(state, castNode(NullTest, node)); + break; + case T_BooleanTest: + deparseBooleanTest(state, castNode(BooleanTest, node)); + break; + case T_JsonIsPredicate: + deparseJsonIsPredicate(state, castNode(JsonIsPredicate, node)); + break; + case T_SetToDefault: + deparseSetToDefault(state, castNode(SetToDefault, node)); + break; + case T_MergeSupportFunc: + deparseAppendStringInfoString(state, "merge_action() "); + break; + case T_JsonParseExpr: + deparseJsonParseExpr(state, castNode(JsonParseExpr, node)); + break; + case T_JsonScalarExpr: + deparseJsonScalarExpr(state, castNode(JsonScalarExpr, node)); + break; + case T_JsonSerializeExpr: + deparseJsonSerializeExpr(state, castNode(JsonSerializeExpr, node)); + break; + case T_JsonFuncExpr: + deparseJsonFuncExpr(state, castNode(JsonFuncExpr, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(state, node, context); + break; + default: + // Note that this is also the fallthrough for deparseBExpr and deparseCExpr + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr/c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "b_expr" in gram.y +static void deparseBExpr(DeparseState *state, Node *node) +{ + if (IsA(node, XmlExpr)) { + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE); + return; + } + + if (IsA(node, A_Expr)) { + A_Expr *a_expr = castNode(A_Expr, node); + // Other kinds are handled by "c_expr", with parens added around them + if (a_expr->kind == AEXPR_OP || a_expr->kind == AEXPR_DISTINCT || a_expr->kind == AEXPR_NOT_DISTINCT) { + deparseAExpr(state, a_expr, DEPARSE_NODE_CONTEXT_NONE); + return; + } + } + + if (IsA(node, BoolExpr)) { + BoolExpr *bool_expr = castNode(BoolExpr, node); + if (bool_expr->boolop == NOT_EXPR) { + deparseBoolExpr(state, bool_expr); + return; + } + } + + deparseCExpr(state, node); +} + +// "AexprConst" in gram.y +static void deparseAexprConst(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_A_Const: + deparseAConst(state, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + default: + elog(ERROR, "deparse: unpermitted node type in AexprConst: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(state, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(state, castNode(A_Const, node)); + break; + case T_ParamRef: + deparseParamRef(state, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(state, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(state, castNode(CaseExpr, node)); + break; + case T_SubLink: + deparseSubLink(state, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(state, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(state, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(state, castNode(GroupingFunc, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(state, node, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + deparseAppendStringInfoChar(state, '('); + // Because we wrap this in parenthesis, the expression inside follows "a_expr" parser rules + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(DeparseState *state, char *s) +{ + deparseAppendStringInfoString(state, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(DeparseState *state, char *s) +{ + deparseAppendStringInfoString(state, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(DeparseState *state, Node *node) +{ + deparseAppendStringInfo(state, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(DeparseState *state, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + deparseAppendStringInfoChar(state, '.'); + deparseColLabel(state, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + deparseAppendStringInfoString(state, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(state, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(DeparseState *state, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(state, role_spec); + if (lnext(roles, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(DeparseState *state, Node *node) +{ + deparseTypeName(state, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(DeparseState *state, union ValUnion *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + deparseAppendStringInfo(state, "%d", value->ival.ival); + break; + case T_Float: + deparseAppendStringInfoString(state, value->sval.sval); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(state, (union ValUnion *) lfirst(lc)); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(DeparseState *state, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + deparseAppendStringInfoString(state, "AS "); + deparseSimpleTypename(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + deparseAppendStringInfoString(state, "CACHE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + deparseAppendStringInfoString(state, "INCREMENT "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "MAXVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "MINVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + deparseAppendStringInfoString(state, "OWNED BY "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + deparseAppendStringInfoString(state, "SEQUENCE NAME "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + deparseAppendStringInfoString(state, "START "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(DeparseState *state, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(state, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseSeqOptList(state, options); + deparseAppendStringInfoChar(state, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(DeparseState *state, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + deparseAppendStringInfoString(state, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(DeparseState *state, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(op)))); + deparseAppendStringInfoChar(state, '.'); + deparseAppendStringInfoString(state, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + deparseAppendStringInfoString(state, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(DeparseState *state, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + deparseAppendStringInfoString(state, strVal(linitial(op))); + } + else + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(DeparseState *state, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + deparseAppendStringInfoString(state, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + deparseAppendStringInfoString(state, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + deparseAppendStringInfoString(state, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + deparseAppendStringInfoString(state, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + deparseAppendStringInfoString(state, strVal(linitial(op))); + } + else + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(DeparseState *state, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + deparseAppendStringInfoString(state, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(DeparseState *state, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(state, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, l); + deparseAppendStringInfoChar(state, ')'); + } + else if (list_length(l) == 1) + { + deparseAppendStringInfoString(state, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(state, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + deparseAppendStringInfoString(state, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + deparseAppendStringInfoString(state, s); + } + else // Sconst + { + deparseStringLiteral(state, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoChar(state, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + deparseAppendStringInfoString(state, " = "); + deparseDefArg(state, def_elem->arg, false); + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + { + deparseAppendStringInfoString(state, "WITH "); + deparseDefinition(state, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + deparseAppendStringInfoString(state, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ")"); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + deparseAppendStringInfoString(state, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + deparseAppendStringInfoString(state, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + deparseAppendStringInfoString(state, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + deparseAppendStringInfoString(state, "COST "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + deparseAppendStringInfoString(state, "ROWS "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + deparseAppendStringInfoString(state, "SUPPORT "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(state, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + deparseAppendStringInfoString(state, "PARALLEL "); + deparseAppendStringInfoString(state, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(DeparseState *state, const char *val) +{ + if (strlen(val) == 0) + deparseAppendStringInfoString(state, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(state, val); + else + deparseAppendStringInfoString(state, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + deparseAppendStringInfoString(state, "$$"); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, "$$"); + } + else + { + deparseStringLiteral(state, strval); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(DeparseState *state, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + deparseAppendStringInfoString(state, "AS "); + deparseFuncAs(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoString(state, "TRANSFORM "); + foreach (lc, l) + { + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + deparseAppendStringInfoString(state, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(state, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + deparseAppendStringInfoString(state, "ADD "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + deparseAppendStringInfoString(state, "DROP "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(DeparseState *state, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(state, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + deparseAppendStringInfoChar(state, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(DeparseState *state, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(state, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + deparseAppendStringInfoChar(state, '('); + if (linitial(object_with_args->objargs) == NULL) + deparseAppendStringInfoString(state, "NONE"); + else + deparseTypeName(state, castNode(TypeName, linitial(object_with_args->objargs))); + deparseAppendStringInfoString(state, ", "); + if (lsecond(object_with_args->objargs) == NULL) + deparseAppendStringInfoString(state, "NONE"); + else + deparseTypeName(state, castNode(TypeName, lsecond(object_with_args->objargs))); + deparseAppendStringInfoChar(state, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(DeparseState *state, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + deparseAppendStringInfoChar(state, '('); + if (args == NULL) + { + deparseAppendStringInfoChar(state, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + deparseAppendStringInfoString(state, ", "); + } + + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + deparseAppendStringInfoString(state, " ORDER BY "); + deparseFunctionParameter(state, castNode(FunctionParameter, llast(args))); + } + } + deparseAppendStringInfoChar(state, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(state, object_with_args->objname); + + deparseAppendStringInfoChar(state, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + deparseAppendStringInfoChar(state, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(DeparseState *state, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "opt_column_and_period_list" and "optionalPeriodName" in gram.y +static void deparseColumnListWithPeriod(DeparseState *state, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + bool not_last = lnext(columns, lc); + if (!not_last) + deparseAppendStringInfoString(state, "PERIOD "); + + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + + if (not_last) + deparseAppendStringInfoString(state, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(DeparseState *state, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + deparseAppendStringInfoString(state, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + deparseAppendStringInfoString(state, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(DeparseState *state, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(DeparseState *state, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(DeparseState *state, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(DeparseState *state, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(DeparseState *state, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + deparseAppendStringInfoString(state, "TRUE"); + else if (strcmp(s, "false") == 0) + deparseAppendStringInfoString(state, "FALSE"); + else if (strcmp(s, "on") == 0) + deparseAppendStringInfoString(state, "ON"); + else if (strcmp(s, "off") == 0) + deparseAppendStringInfoString(state, "OFF"); + else + deparseNonReservedWordOrSconst(state, s); +} + +static void deparseOptBoolean(DeparseState *state, Node *node) +{ + if (node == NULL) + { + return; + } + + switch (nodeTag(node)) + { + case T_String: + deparseAppendStringInfo(state, " %s", strVal(node)); + break; + case T_Integer: + deparseAppendStringInfo(state, " %d", intVal(node)); + break; + case T_Boolean: + deparseAppendStringInfo(state, " %s", boolVal(node) ? "TRUE" : "FALSE"); + break; + default: + Assert(false); + break; + } +} + +bool optBooleanValue(Node *node) +{ + if (node == NULL) + { + return true; + } + + switch (nodeTag(node)) + { + case T_String: { + // Longest valid string is "off\0" + char lower[4]; + strncpy(lower, strVal(node), 4); + lower[3] = 0; + + if (strcmp(lower, "on") == 0) { + return true; + } else if (strcmp(lower, "off") == 0) { + return false; + } + + // No sane way to handle this. + return false; + } + case T_Integer: + return intVal(node) != 0; + case T_Boolean: + return boolVal(node); + default: + Assert(false); + return false; + } +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(DeparseState *state, char *s) +{ + deparseColId(state, s); +} + +// "var_list" +static void deparseVarList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(state, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(state, (union ValUnion *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(state, strVal(&a_const->val)); + else + Assert(false); + } + else if (IsA(lfirst(lc), TypeCast)) + { + deparseTypeCast(state, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + deparseAppendStringInfoString(state, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + deparseAppendStringInfoString(state, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + deparseAppendStringInfoString(state, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + deparseAppendStringInfoString(state, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + deparseAppendStringInfoString(state, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + deparseAppendStringInfoString(state, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + deparseAppendStringInfoString(state, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + deparseAppendStringInfoString(state, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + deparseAppendStringInfoString(state, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + deparseAppendStringInfoString(state, "SET GENERATED "); + if (def_elem->arg == NULL) + elog(ERROR, "deparse: missing argument for identity generation specification"); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + deparseAppendStringInfoString(state, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + deparseAppendStringInfoString(state, "BY DEFAULT"); + else + Assert(false); + } + else + { + deparseAppendStringInfoString(state, "SET "); + deparseSeqOptElem(state, def_elem); + } + if (lnext(l, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoChar(state, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(def_elem->defnamespace)); + deparseAppendStringInfoChar(state, '.'); + } + if (def_elem->defname != NULL) + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + deparseAppendStringInfoChar(state, '='); + if (def_elem->arg != NULL) + deparseDefArg(state, def_elem->arg, false); + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "WITH "); + deparseRelOptions(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(state, castNode(ColumnRef, res_target->val)); + else + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (res_target->name != NULL) { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + deparseOptIndirection(state, res_target->indirection, 0); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (res_target->name != NULL) + { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + + if (res_target->name != NULL) + { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(state, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(state, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(state, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(state, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(state, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(state, castNode(JoinExpr, node)); + break; + case T_JsonTable: + deparseJsonTable(state, castNode(JsonTable, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(state, lfirst(lc)); + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendPartGroup(state, "FROM", DEPARSE_PART_INDENT); + deparseFromList(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(DeparseState *state, Node *node) +{ + if (node != NULL) + { + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "where_or_current_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereOrCurrentClause(DeparseState *state, Node *node) +{ + if (node == NULL) + return; + + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); + + if (IsA(node, CurrentOfExpr)) { + CurrentOfExpr *current_of_expr = castNode(CurrentOfExpr, node); + deparseAppendStringInfoString(state, "CURRENT OF "); + deparseAppendStringInfoString(state, quote_identifier(current_of_expr->cursor_name)); + } else { + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + deparseAppendStringInfoChar(state, ' '); +} + +// "group_by_list" in gram.y +static void deparseGroupByList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(state, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(DeparseState *state, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(state, res_target->name); + deparseOptIndirection(state, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(state, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(state, strVal(lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "opt_sort_clause" and "json_array_aggregate_order_by_clause_opt" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(DeparseState *state, List *l, DeparseNodeContext context) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendPartGroup(state, "ORDER BY", DEPARSE_PART_INDENT_AND_MERGE); + else + deparseAppendStringInfoString(state, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(state, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + { + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendCommaAndPart(state); + else + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(DeparseState *state, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + deparseAppendStringInfoString(state, named_arg_expr->name); + deparseAppendStringInfoString(state, " := "); + deparseExpr(state, (Node *) named_arg_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + } + else + { + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(DeparseState *state, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + deparseAppendCommaAndPart(state); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + deparseAppendStringInfoString(state, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(state, castNode(ResTarget, lfirst(lc2))); + if ((foreach_current_index(lc2) - foreach_current_index(lc)) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") = "); + deparseExpr(state, r->source, DEPARSE_NODE_CONTEXT_A_EXPR); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(state, res_target); + deparseAppendStringInfoString(state, " = "); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(DeparseState *state, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(state, castNode(FuncCall, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + break; + case T_XmlSerialize: + deparseXmlSerialize(state, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(state, index_elem->name); + deparseAppendStringInfoChar(state, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + // Simple function calls can be written without wrapping parens + case T_FuncCall: // func_application + case T_SQLValueFunction: // func_expr_common_subexpr + case T_CoalesceExpr: // func_expr_common_subexpr + case T_MinMaxExpr: // func_expr_common_subexpr + case T_XmlExpr: // func_expr_common_subexpr + case T_XmlSerialize: // func_expr_common_subexpr + deparseFuncExprWindowless(state, index_elem->expr); + deparseAppendStringInfoString(state, " "); + break; + default: + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, index_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(state, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(state, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(state, index_elem->opclassopts); + + deparseAppendStringInfoChar(state, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + deparseAppendStringInfoString(state, "ASC "); + break; + case SORTBY_DESC: + deparseAppendStringInfoString(state, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + deparseAppendStringInfoString(state, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + deparseAppendStringInfoString(state, "NULLS LAST "); + break; + } + + removeTrailingSpace(state); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "INHERITS ("); + deparseQualifiedNameList(state, l); + deparseAppendStringInfoString(state, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(DeparseState *state, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(state, objs); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseQualifiedNameList(state, objs); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseNameList(state, objs); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "FOREIGN SERVER "); + deparseNameList(state, objs); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseNameList(state, objs); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyNameList(state, objs); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNameList(state, objs); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnlyList(state, objs); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseNameList(state, objs); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyNameList(state, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "ALL TABLES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ALL ROUTINES IN SCHEMA "); + deparseNameList(state, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLES"); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCES"); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPES"); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMAS"); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECTS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(DeparseState *state, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(state, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + deparseAppendStringInfoString(state, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(state, def_elem->defname); + + deparseAppendStringInfoChar(state, ' '); + + if (def_elem->arg == NULL) + deparseAppendStringInfoString(state, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(state, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + + if (lnext(l, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(state, def_elem->defname); + + if (def_elem->arg != NULL) + { + deparseAppendStringInfoChar(state, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } +} + +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + bool need_parens = context == DEPARSE_NODE_CONTEXT_SELECT_SETOP && ( + list_length(stmt->sortClause) > 0 || + stmt->limitOffset != NULL || + stmt->limitCount != NULL || + list_length(stmt->lockingClause) > 0 || + stmt->withClause != NULL || + stmt->op != SETOP_NONE); + DeparseStateNestingLevel *parent_level = NULL; + + if (need_parens) + { + deparseAppendPart(state, true); + deparseAppendStringInfoChar(state, '('); + } + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + parent_level = deparseStateIncreaseNestingLevel(state); + + if (stmt->withClause) + { + deparseWithClause(state, stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + deparseAppendPartGroup(state, "VALUES", DEPARSE_PART_INDENT_AND_MERGE); + + foreach(lc, stmt->valuesLists) + { + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ')'); + if (lnext(stmt->valuesLists, lc)) + deparseAppendCommaAndPart(state); + } + deparseAppendStringInfoChar(state, ' '); + break; + } + + deparseAppendPartGroup(state, "SELECT", DEPARSE_PART_INDENT_AND_MERGE); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + deparseMarkCurrentPartNonMergable(state); + deparseAppendStringInfoString(state, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + deparseAppendStringInfoString(state, "ON ("); + deparseExprList(state, stmt->distinctClause); + deparseAppendStringInfoString(state, ") "); + } + deparseAppendPart(state, true); + } + + deparseTargetList(state, stmt->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->intoClause != NULL) + { + deparseAppendPartGroup(state, "INTO", DEPARSE_PART_INDENT); + deparseOptTemp(state, stmt->intoClause->rel->relpersistence); + deparseIntoClause(state, stmt->intoClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseFromClause(state, stmt->fromClause); + deparseWhereClause(state, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + deparseAppendPartGroup(state, "GROUP BY", DEPARSE_PART_INDENT_AND_MERGE); + if (stmt->groupDistinct) + deparseAppendStringInfoString(state, "DISTINCT "); + deparseGroupByList(state, stmt->groupClause); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->havingClause != NULL) + { + deparseAppendPartGroup(state, "HAVING", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->havingClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->windowClause != NULL) + { + deparseAppendPartGroup(state, "WINDOW", DEPARSE_PART_INDENT); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + deparseAppendStringInfoString(state, window_def->name); + deparseAppendStringInfoString(state, " AS "); + deparseWindowDef(state, window_def); + if (lnext(stmt->windowClause, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + deparseSelectStmt(state, stmt->larg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); + switch (stmt->op) + { + case SETOP_UNION: + if (stmt->all) + deparseAppendPartGroup(state, "UNION ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "UNION", DEPARSE_PART_NO_INDENT); + break; + case SETOP_INTERSECT: + if (stmt->all) + deparseAppendPartGroup(state, "INTERSECT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "INTERSECT", DEPARSE_PART_NO_INDENT); + break; + case SETOP_EXCEPT: + if (stmt->all) + deparseAppendPartGroup(state, "EXCEPT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "EXCEPT", DEPARSE_PART_NO_INDENT); + break; + default: + Assert(false); + } + deparseAppendPart(state, true); + deparseSelectStmt(state, stmt->rarg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); + deparseAppendStringInfoChar(state, ' '); + } + break; + } + + deparseOptSortClause(state, stmt->sortClause, DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + deparseAppendPartGroup(state, "LIMIT", DEPARSE_PART_INDENT); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseAppendStringInfoString(state, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) + deparseAppendStringInfoString(state, "ALL"); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseCExpr(state, stmt->limitCount); + else + deparseExpr(state, stmt->limitCount, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + + deparseAppendStringInfoChar(state, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseAppendStringInfoString(state, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + deparseAppendPartGroup(state, "OFFSET", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->limitOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(state, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + deparseAppendStringInfoString(state, " "); + } + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); + + /* Note that parent_level can be NULL, so we repeat the full if condition here */ + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + deparseStateDecreaseNestingLevel(state, parent_level); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(state, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, into_clause->colNames); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + + if (into_clause->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->accessMethod)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseOptWith(state, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + deparseAppendStringInfoString(state, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->tableSpaceName)); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ONLY "); + + if (range_var->catalogname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(range_var->catalogname)); + deparseAppendStringInfoChar(state, '.'); + } + + if (range_var->schemaname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(range_var->schemaname)); + deparseAppendStringInfoChar(state, '.'); + } + + Assert(range_var->relname != NULL); + deparseAppendStringInfoString(state, quote_identifier(range_var->relname)); + deparseAppendStringInfoChar(state, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_var->alias); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt) +{ + PostgresDeparseOpts opts; + MemSet(&opts, 0, sizeof(PostgresDeparseOpts)); // zero initialized means pretty print = false + deparseRawStmtOpts(str, raw_stmt, &opts); +} + +void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts *opts) +{ + DeparseState *state = NULL; + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + state = palloc0(sizeof(DeparseState)); + state->opts = opts; + if (state->opts->indent_size == 0) + state->opts->indent_size = 4; + if (state->opts->max_line_length == 0) + state->opts->max_line_length = 80; + + /* Check for any comments at the start of the statement */ + if (state->opts->comment_count > 0) + { + deparseStateIncreaseNestingLevel(state); + deparseAppendCommentsIfNeeded(state, raw_stmt->stmt_location); + deparseRemoveTrailingEmptyPart(state); + deparseStateDecreaseNestingLevel(state, NULL); + } + + deparseStmt(state, raw_stmt->stmt); + + /* Check for any comments at the end of the statement */ + if (state->opts->comment_count > 0) + { + deparseStateIncreaseNestingLevel(state); + deparseAppendCommentsIfNeeded(state, INT_MAX); + deparseRemoveTrailingEmptyPart(state); + deparseStateDecreaseNestingLevel(state, NULL); + } + + deparseEmit(state, str); + + bms_free(state->emitted_comments); + pfree(state); +} + +static void deparseAlias(DeparseState *state, Alias *alias) +{ + deparseAppendStringInfoString(state, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, alias->colnames); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseAConst(DeparseState *state, A_Const *a_const) +{ + union ValUnion *val = a_const->isnull ? NULL : &a_const->val; + deparseAppendCommentsIfNeeded(state, a_const->location); + deparseValue(state, val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "OVERLAY("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PLACING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + deparseAppendStringInfoString(state, "SUBSTRING("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(func_call->args) == 3) + { + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + deparseAppendStringInfoString(state, "POSITION("); + deparseBExpr(state, lsecond(func_call->args)); + deparseAppendStringInfoString(state, " IN "); + deparseBExpr(state, linitial(func_call->args)); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "overlay("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " placing "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " from "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "collation for ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + deparseAppendStringInfoString(state, "extract ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + + deparseAppendStringInfoString(state, "overlaps "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + deparseAppendStringInfoString(state, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + deparseAppendStringInfoString(state, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + deparseAppendStringInfoString(state, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + deparseAppendStringInfoString(state, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) > 0 && + list_length(func_call->args) <= 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + Expr* e; + bool isLocal = list_length(func_call->args) == 1; + + if (isLocal) + e = linitial(func_call->args); + else + e = lsecond(func_call->args); + + // If we're not inside an a_expr context, we must add wrapping parenthesis around the AT ... syntax + if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { + deparseAppendStringInfoChar(state, '('); + } + + if (IsA(e, A_Expr)) { + deparseAppendStringInfoChar(state, '('); + } + + deparseExpr(state, (Node*) e, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (IsA(e, A_Expr)) { + deparseAppendStringInfoChar(state, ')'); + } + + if (isLocal) + deparseAppendStringInfoString(state, " AT LOCAL"); + else { + deparseAppendStringInfoString(state, " AT TIME ZONE "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + + if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { + deparseAppendStringInfoChar(state, ')'); + } + + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + deparseAppendStringInfoString(state, "normalize ("); + + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(func_call->args) == 2) + { + deparseAppendStringInfoString(state, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + deparseAppendStringInfoString(state, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + deparseAppendStringInfoString(state, "xmlexists ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "system_user") == 0) + { + deparseAppendStringInfoString(state, "SYSTEM_USER"); + return; + } + + deparseFuncName(state, func_call->funcname); + deparseAppendStringInfoChar(state, '('); + + if (func_call->agg_distinct) + deparseAppendStringInfoString(state, "DISTINCT "); + + if (func_call->agg_star) + { + deparseAppendStringInfoChar(state, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + deparseAppendStringInfoString(state, "VARIADIC "); + deparseFuncArgExpr(state, lfirst(lc)); + if (lnext(func_call->args, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); + } + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + deparseAppendStringInfoString(state, "WITHIN GROUP ("); + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + } + + if (func_call->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, func_call->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (func_call->over) + { + deparseAppendStringInfoString(state, "OVER "); + if (func_call->over->name) + deparseAppendStringInfoString(state, func_call->over->name); + else + deparseWindowDef(state, func_call->over); + } + + removeTrailingSpace(state); +} + +static void deparseWindowDef(DeparseState *state, WindowDef* window_def) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + // The parent node is responsible for outputting window_def->name + + // Special case completely empty window clauses and return early + if (!window_def->refname && list_length(window_def->partitionClause) == 0 && + list_length(window_def->orderClause) == 0 && + !(window_def->frameOptions & FRAMEOPTION_NONDEFAULT)) + { + deparseAppendStringInfoString(state, "()"); + return; + } + + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); + + if (window_def->refname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(window_def->refname)); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + deparseAppendStringInfoString(state, "PARTITION BY "); + deparseExprList(state, window_def->partitionClause); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); + deparseAppendPart(state, true); + deparseOptSortClause(state, window_def->orderClause, DEPARSE_NODE_CONTEXT_NONE); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + deparseAppendPartGroup(state, NULL, DEPARSE_PART_NO_INDENT); + if (window_def->frameOptions & FRAMEOPTION_RANGE) + deparseAppendStringInfoString(state, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + deparseAppendStringInfoString(state, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + deparseAppendStringInfoString(state, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + deparseAppendStringInfoString(state, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + deparseAppendStringInfoString(state, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + deparseAppendStringInfoString(state, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + deparseAppendStringInfoString(state, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + deparseAppendStringInfoString(state, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + deparseAppendStringInfoString(state, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + deparseAppendStringInfoString(state, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + deparseAppendStringInfoString(state, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + deparseAppendStringInfoString(state, "EXCLUDE TIES "); + } + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + deparseAppendCommentsIfNeeded(state, column_ref->location); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(state, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(state, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(state, column_ref->fields, 1); +} + +static void deparseSubLink(DeparseState *state, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + deparseAppendStringInfoString(state, "EXISTS ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ALL_SUBLINK: + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ALL ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ANY_SUBLINK: + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(sub_link->operName) > 0) + { + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ANY "); + } + else + { + deparseAppendStringInfoString(state, " IN "); + } + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + deparseAppendStringInfoString(state, "("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + deparseAppendStringInfoString(state, "ARRAY("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +// Checks whether a node needs parens when used in a "b_expr" context (because the node is handled by the "a_expr" rule in gram.y) +static bool +needsParensAsBExpr(Node *node) +{ + if (node == NULL) + return false; + return IsA(node, BoolExpr) || IsA(node, BooleanTest) || IsA(node, NullTest) || IsA(node, A_Expr); +} + +// This handles "A_Expr" parse tree objects, which are a subset of the rules in "a_expr" (handled by deparseExpr) +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = needsParensAsBExpr(a_expr->lexpr); + bool need_rexpr_parens = needsParensAsBExpr(a_expr->rexpr); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + } + deparseQualOp(state, a_expr->name); + if (a_expr->rexpr != NULL) + { + deparseAppendStringInfoChar(state, ' '); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, ')'); + } + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ANY("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ALL("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoString(state, " IS DISTINCT FROM "); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, " IS NOT DISTINCT FROM "); + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseAppendStringInfoString(state, "NULLIF("); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "=") == 0) { + deparseAppendStringInfoString(state, "IN "); + } else if (strcmp(name, "<>") == 0) { + deparseAppendStringInfoString(state, "NOT IN "); + } else { + Assert(false); + } + deparseAppendStringInfoChar(state, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(state, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(state, castNode(List, a_expr->rexpr)); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~") == 0) { + deparseAppendStringInfoString(state, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + deparseAppendStringInfoString(state, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~*") == 0) { + deparseAppendStringInfoString(state, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + deparseAppendStringInfoString(state, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~") == 0) { + deparseAppendStringInfoString(state, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + deparseAppendStringInfoString(state, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(state, linitial(n->args), context); + if (list_length(n->args) == 2) + { + deparseAppendStringInfoString(state, " ESCAPE "); + deparseExpr(state, lsecond(n->args), context); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, strVal(linitial(a_expr->name))); + deparseAppendStringInfoChar(state, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(state, lfirst(lc), context); + if (lnext(castNode(List, a_expr->rexpr), lc)) + deparseAppendStringInfoString(state, " AND "); + } + return; + } +} + +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + if (lnext(bool_expr->args, lc)) + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, "AND "); + } + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + if (lnext(bool_expr->args, lc)) + deparseAppendStringInfoString(state, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + deparseAppendStringInfoString(state, "NOT "); + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(bool_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + return; + } +} + +static void deparseAStar(DeparseState *state, A_Star *a_star) +{ + deparseAppendStringInfoChar(state, '*'); +} + +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, collate_clause->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + } + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, collate_clause->collname); +} + +// "sortby" in gram.y +static void deparseSortBy(DeparseState *state, SortBy* sort_by) +{ + deparseExpr(state, sort_by->node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + deparseAppendStringInfoString(state, "ASC "); + break; + case SORTBY_DESC: + deparseAppendStringInfoString(state, "DESC "); + break; + case SORTBY_USING: + deparseAppendStringInfoString(state, "USING "); + deparseQualOp(state, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + deparseAppendStringInfoString(state, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + deparseAppendStringInfoString(state, "NULLS LAST "); + break; + } + + removeTrailingSpace(state); +} + +static void deparseParamRef(DeparseState *state, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + deparseAppendStringInfoChar(state, '?'); + } else { + deparseAppendStringInfo(state, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + deparseAppendStringInfoString(state, "current_date"); + break; + case SVFOP_CURRENT_TIME: + deparseAppendStringInfoString(state, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + deparseAppendStringInfoString(state, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + deparseAppendStringInfoString(state, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + deparseAppendStringInfoString(state, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + deparseAppendStringInfoString(state, "localtime"); + break; + case SVFOP_LOCALTIME_N: + deparseAppendStringInfoString(state, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + deparseAppendStringInfoString(state, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + deparseAppendStringInfoString(state, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + deparseAppendStringInfoString(state, "current_role"); + break; + case SVFOP_CURRENT_USER: + deparseAppendStringInfoString(state, "current_user"); + break; + case SVFOP_USER: + deparseAppendStringInfoString(state, "user"); + break; + case SVFOP_SESSION_USER: + deparseAppendStringInfoString(state, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + deparseAppendStringInfoString(state, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + deparseAppendStringInfoString(state, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + deparseAppendStringInfo(state, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(DeparseState *state, WithClause *with_clause) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "WITH", DEPARSE_PART_NO_INDENT); + if (with_clause->recursive) + deparseAppendStringInfoString(state, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(state, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + deparseAppendStringInfoString(state, ", "); + } + + removeTrailingSpace(state); +} + +// "joined_table" in gram.y +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + deparseAppendStringInfoChar(state, '('); + + deparseTableRef(state, join_expr->larg); + deparseAppendPart(state, true); + + if (join_expr->isNatural) + deparseAppendStringInfoString(state, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + deparseAppendStringInfoString(state, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + deparseAppendStringInfoString(state, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + deparseAppendStringInfoString(state, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + deparseAppendStringInfoString(state, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_RIGHT_SEMI: + case JOIN_RIGHT_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + deparseAppendStringInfoString(state, "JOIN "); + + if (need_rarg_parens) + deparseAppendStringInfoChar(state, '('); + deparseTableRef(state, join_expr->rarg); + if (need_rarg_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + + if (join_expr->quals != NULL) + { + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, join_expr->quals, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + deparseAppendStringInfoString(state, "USING ("); + deparseNameList(state, join_expr->usingClause); + deparseAppendStringInfoString(state, ") "); + + if (join_expr->join_using_alias) + { + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoString(state, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + deparseAppendStringInfoString(state, ") "); + + if (join_expr->alias != NULL) + deparseAlias(state, join_expr->alias); + + removeTrailingSpace(state); +} + +static void deparseCTESearchClause(DeparseState *state, CTESearchClause *search_clause) +{ + deparseAppendStringInfoString(state, " SEARCH "); + if (search_clause->search_breadth_first) + deparseAppendStringInfoString(state, "BREADTH "); + else + deparseAppendStringInfoString(state, "DEPTH "); + + deparseAppendStringInfoString(state, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(state, search_clause->search_col_list); + + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(search_clause->search_seq_column)); +} + +// "opt_cycle_clause" in gram.y +static void deparseCTECycleClause(DeparseState *state, CTECycleClause *cycle_clause) +{ + deparseAppendStringInfoString(state, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(state, cycle_clause->cycle_col_list); + + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + deparseAppendStringInfoString(state, " TO "); + deparseAexprConst(state, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + deparseAppendStringInfoString(state, " DEFAULT "); + deparseAexprConst(state, cycle_clause->cycle_mark_default); + } + + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte) +{ + deparseAppendCommentsIfNeeded(state, cte->location); + + deparseColId(state, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, cte->aliascolnames); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + deparseAppendStringInfoString(state, "MATERIALIZED "); + break; + case CTEMaterializeNever: + deparseAppendStringInfoString(state, "NOT MATERIALIZED "); + break; + } + + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, cte->ctequery); + deparseAppendStringInfoChar(state, ')'); + + if (cte->search_clause) + deparseCTESearchClause(state, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(state, cte->cycle_clause); +} + +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, range_subselect->subquery), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + + if (range_subselect->alias != NULL) + { + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, range_subselect->alias); + } +} + +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + if (range_func->is_rowsfrom) + { + deparseAppendStringInfoString(state, "ROWS FROM "); + deparseAppendStringInfoChar(state, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(state, linitial(lfunc)); + deparseAppendStringInfoChar(state, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + deparseAppendStringInfoString(state, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + if (lnext(range_func->functions, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(state, linitial(linitial(range_func->functions))); + } + deparseAppendStringInfoChar(state, ' '); + + if (range_func->ordinality) + deparseAppendStringInfoString(state, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(state, range_func->alias); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoChar(state, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ARRAY["); + deparseExprList(state, array_expr->elements); + deparseAppendStringInfoChar(state, ']'); +} + +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + deparseAppendStringInfoString(state, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + deparseAppendStringInfoString(state, "("); + deparseExprList(state, row_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context) +{ + bool need_parens = needsParensAsBExpr(type_cast->arg); + + Assert(type_cast->typeName != NULL); + + if (context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + { + deparseAppendStringInfoString(state, "CAST("); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, type_cast->typeName); + deparseAppendStringInfoChar(state, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + deparseAppendStringInfoString(state, "char "); + deparseAConst(state, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + deparseAppendStringInfoString(state, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + deparseAppendStringInfoString(state, "false"); + return; + } + } + else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) + { + deparseAppendStringInfoString(state, "interval "); + deparseAConst(state, a_const); + deparseIntervalTypmods(state, type_cast->typeName); + return; + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + deparseAppendStringInfoString(state, " point "); + deparseAConst(state, a_const); + return; + } + } + + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_NONE /* could be either a_expr or b_expr (we could pass this down, but that'd require two kinds of contexts most likely) */); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + deparseAppendStringInfoString(state, "::"); + deparseTypeName(state, type_cast->typeName); +} + +static void deparseTypeName(DeparseState *state, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + deparseAppendStringInfoString(state, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + deparseAppendStringInfoString(state, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + deparseAppendStringInfoString(state, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + deparseAppendStringInfoString(state, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + deparseAppendStringInfoString(state, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + deparseAppendStringInfoString(state, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + deparseAppendStringInfoString(state, "int"); + } + else if (strcmp(name, "int8") == 0) + { + deparseAppendStringInfoString(state, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + deparseAppendStringInfoString(state, "real"); + } + else if (strcmp(name, "float8") == 0) + { + deparseAppendStringInfoString(state, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + deparseAppendStringInfoString(state, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + deparseAppendStringInfoString(state, "time "); + if (list_length(type_name->typmods) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + deparseAppendStringInfoString(state, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + deparseAppendStringInfoString(state, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + deparseAppendStringInfoString(state, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + deparseAppendStringInfoString(state, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + deparseAppendStringInfoString(state, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + deparseAppendStringInfoString(state, "interval"); + deparseIntervalTypmods(state, type_name); + + skip_typmods = true; + } + else + { + deparseAppendStringInfoString(state, "pg_catalog."); + deparseAppendStringInfoString(state, name); + } + } + else + { + deparseAnyName(state, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(state, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(state, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(state, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + deparseAppendStringInfoChar(state, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ']'); + } + + if (type_name->pct_type) + deparseAppendStringInfoString(state, "%type"); +} + +// Handle typemods for Interval types separately +// so that they can be applied appropriately for different contexts. +// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` +// the `INTERVAL` keyword is specified first. +// In all other contexts, intervals use the `'x'::interval` style. +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name) +{ + const char *name = strVal(lsecond(type_name->names)); + Assert(strcmp(name, "interval") == 0); + Assert(list_length(type_name->typmods) >= 1); + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + deparseAppendStringInfoString(state, " year"); + break; + case INTERVAL_MASK(MONTH): + deparseAppendStringInfoString(state, " month"); + break; + case INTERVAL_MASK(DAY): + deparseAppendStringInfoString(state, " day"); + break; + case INTERVAL_MASK(HOUR): + deparseAppendStringInfoString(state, " hour"); + break; + case INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " minute"); + break; + case INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + deparseAppendStringInfoString(state, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + deparseAppendStringInfoString(state, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + deparseAppendStringInfo(state, "(%d)", precision); + } +} + +static void deparseNullTest(DeparseState *state, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(state, (Node *) null_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + switch (null_test->nulltesttype) + { + case IS_NULL: + deparseAppendStringInfoString(state, " IS NULL"); + break; + case IS_NOT_NULL: + deparseAppendStringInfoString(state, " IS NOT NULL"); + break; + } +} + +// "case_expr" in gram.y +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(state, (Node *) case_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + parent_level = deparseStateIncreaseNestingLevel(state); + + foreach(lc, case_expr->args) + { + deparseCaseWhen(state, castNode(CaseWhen, lfirst(lc))); + } + + if (case_expr->defresult != NULL) + { + deparseAppendPartGroup(state, "ELSE", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_expr->defresult, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + deparseAppendStringInfoChar(state, ' '); + deparseStateDecreaseNestingLevel(state, parent_level); + + deparseAppendStringInfoString(state, "END"); +} + +// "when_clause" in gram.y +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when) +{ + deparseAppendPartGroup(state, "WHEN", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_when->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " THEN "); + deparseExpr(state, (Node *) case_when->result, DEPARSE_NODE_CONTEXT_A_EXPR); +} + +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + IsA(a_indirection->arg, A_ArrayExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)) || + IsA(a_indirection->arg, JsonFuncExpr); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, a_indirection->arg, need_parens ? DEPARSE_NODE_CONTEXT_A_EXPR : DEPARSE_NODE_CONTEXT_NONE); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + deparseOptIndirection(state, a_indirection->indirection, 0); +} + +static void deparseAIndices(DeparseState *state, A_Indices *a_indices) +{ + deparseAppendStringInfoChar(state, '['); + if (a_indices->lidx != NULL) + deparseExpr(state, a_indices->lidx, DEPARSE_NODE_CONTEXT_A_EXPR); + if (a_indices->is_slice) + deparseAppendStringInfoChar(state, ':'); + if (a_indices->uidx != NULL) + deparseExpr(state, a_indices->uidx, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ']'); +} + +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr) +{ + deparseAppendStringInfoString(state, "COALESCE("); + deparseExprList(state, coalesce_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + deparseAppendStringInfoString(state, "GREATEST("); + break; + case IS_LEAST: + deparseAppendStringInfoString(state, "LEAST("); + break; + } + deparseExprList(state, min_max_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test) +{ + bool need_parens = IsA(boolean_test->arg, BoolExpr); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, (Node *) boolean_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + switch (boolean_test->booltesttype) + { + case IS_TRUE: + deparseAppendStringInfoString(state, " IS TRUE"); + break; + case IS_NOT_TRUE: + deparseAppendStringInfoString(state, " IS NOT TRUE"); + break; + case IS_FALSE: + deparseAppendStringInfoString(state, " IS FALSE"); + break; + case IS_NOT_FALSE: + deparseAppendStringInfoString(state, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + deparseAppendStringInfoString(state, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + deparseAppendStringInfoString(state, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +// "columnDef" and "alter_table_cmd" in gram.y +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(column_def->colname)); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(state, column_def->typeName); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->storage_name) + { + deparseAppendStringInfoString(state, "STORAGE "); + deparseAppendStringInfoString(state, column_def->storage_name); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->raw_default != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseExpr(state, column_def->raw_default, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->compression != NULL) + { + deparseAppendStringInfoString(state, "COMPRESSION "); + deparseAppendStringInfoString(state, column_def->compression); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(state, column_def->fdwoptions); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(state, castNode(Constraint, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(state, column_def->collClause); + } + + removeTrailingSpace(state); +} + +// "returning_clause" and "returning_option" in gram.y +static void deparseReturningClause(DeparseState *state, ReturningClause *returning_clause) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + if (list_length(returning_clause->options) > 0) + { + deparseAppendStringInfoString(state, "WITH ("); + foreach(lc, returning_clause->options) + { + ReturningOption *opt = castNode(ReturningOption, lfirst(lc)); + switch (opt->option) + { + case RETURNING_OPTION_OLD: + deparseAppendStringInfoString(state, "OLD AS "); + break; + case RETURNING_OPTION_NEW: + deparseAppendStringInfoString(state, "NEW AS "); + break; + } + deparseColId(state, opt->value); + if (lnext(returning_clause->options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + deparseTargetList(state, returning_clause->exprs); +} + +static void deparseInsertOverride(DeparseState *state, OverridingKind override) +{ + switch (override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + deparseAppendStringInfoString(state, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + deparseAppendStringInfoString(state, "OVERRIDING SYSTEM VALUE "); + break; + } +} + +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(state, insert_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "INSERT INTO", DEPARSE_PART_INDENT); + deparseRangeVar(state, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, insert_stmt->cols); + deparseAppendStringInfoString(state, ") "); + } + + deparseInsertOverride(state, insert_stmt->override); + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(state, castNode(SelectStmt, insert_stmt->selectStmt), DEPARSE_NODE_CONTEXT_INSERT_SELECT); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(state, insert_stmt->onConflictClause); + deparseAppendStringInfoChar(state, ' '); + } + + if (insert_stmt->returningClause != NULL) + deparseReturningClause(state, insert_stmt->returningClause); + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseInferClause(DeparseState *state, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(state, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + + if (infer_clause->conname != NULL) + { + deparseAppendStringInfoString(state, "ON CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(infer_clause->conname)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, infer_clause->whereClause); + + removeTrailingSpace(state); +} + +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "ON CONFLICT", DEPARSE_PART_INDENT); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(state, on_conflict_clause->infer); + deparseAppendStringInfoChar(state, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + deparseAppendStringInfoString(state, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + deparseAppendStringInfoString(state, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, on_conflict_clause->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, on_conflict_clause->whereClause); + + removeTrailingSpace(state); +} + +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (update_stmt->withClause != NULL) + { + deparseWithClause(state, update_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "UPDATE", DEPARSE_PART_INDENT); + deparseRangeVar(state, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, update_stmt->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + deparseFromClause(state, update_stmt->fromClause); + deparseWhereOrCurrentClause(state, update_stmt->whereClause); + + if (update_stmt->returningClause != NULL) + deparseReturningClause(state, update_stmt->returningClause); + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +// "MergeStmt" in gram.y +static void deparseMergeStmt(DeparseState *state, MergeStmt *merge_stmt) +{ + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (merge_stmt->withClause != NULL) + { + deparseWithClause(state, merge_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "MERGE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "INTO "); + deparseRangeVar(state, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseTableRef(state, merge_stmt->sourceRelation); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, merge_stmt->joinCondition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + ListCell *lc; + foreach (lc, merge_stmt->mergeWhenClauses) + { + MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); + + deparseAppendStringInfoString(state, "WHEN "); + + switch (clause->matchKind) + { + case MERGE_WHEN_MATCHED: + deparseAppendStringInfoString(state, "MATCHED "); + break; + case MERGE_WHEN_NOT_MATCHED_BY_SOURCE: + deparseAppendStringInfoString(state, "NOT MATCHED BY SOURCE "); + break; + case MERGE_WHEN_NOT_MATCHED_BY_TARGET: + deparseAppendStringInfoString(state, "NOT MATCHED "); + break; + } + + if (clause->condition) + { + deparseAppendStringInfoString(state, "AND "); + deparseExpr(state, clause->condition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "THEN "); + + switch (clause->commandType) { + case CMD_INSERT: + deparseAppendStringInfoString(state, "INSERT "); + + if (clause->targetList) { + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, clause->targetList); + deparseAppendStringInfoString(state, ") "); + } + + deparseInsertOverride(state, clause->override); + + if (clause->values) { + deparseAppendStringInfoString(state, "VALUES ("); + deparseExprList(state, clause->values); + deparseAppendStringInfoString(state, ")"); + } else { + deparseAppendStringInfoString(state, "DEFAULT VALUES "); + } + + break; + case CMD_UPDATE: + deparseAppendStringInfoString(state, "UPDATE SET "); + deparseSetClauseList(state, clause->targetList); + break; + case CMD_DELETE: + deparseAppendStringInfoString(state, "DELETE"); + break; + case CMD_NOTHING: + deparseAppendStringInfoString(state, "DO NOTHING"); + break; + default: + elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); + break; + } + + deparseAppendStringInfoChar(state, ' '); + } + + if (merge_stmt->returningClause != NULL) + deparseReturningClause(state, merge_stmt->returningClause); + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt) +{ + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (delete_stmt->withClause != NULL) + { + deparseWithClause(state, delete_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "DELETE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (delete_stmt->usingClause != NULL) + { + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseFromList(state, delete_stmt->usingClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereOrCurrentClause(state, delete_stmt->whereClause); + + if (delete_stmt->returningClause != NULL) + deparseReturningClause(state, delete_stmt->returningClause); + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + deparseAppendPartGroup(state, "FOR KEY SHARE", DEPARSE_PART_INDENT); + break; + case LCS_FORSHARE: + deparseAppendPartGroup(state, "FOR SHARE", DEPARSE_PART_INDENT); + break; + case LCS_FORNOKEYUPDATE: + deparseAppendPartGroup(state, "FOR NO KEY UPDATE", DEPARSE_PART_INDENT); + break; + case LCS_FORUPDATE: + deparseAppendPartGroup(state, "FOR UPDATE", DEPARSE_PART_INDENT); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + deparseAppendStringInfoString(state, "OF "); + deparseQualifiedNameList(state, locking_clause->lockedRels); + deparseAppendStringInfoChar(state, ' '); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + deparseAppendStringInfoString(state, "NOWAIT"); + break; + case LockWaitSkip: + deparseAppendStringInfoString(state, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(state); +} + +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default) +{ + deparseAppendStringInfoString(state, "DEFAULT"); +} + +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + deparseAppendStringInfoString(state, "CREATE CAST ("); + deparseTypeName(state, create_cast_stmt->sourcetype); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, create_cast_stmt->targettype); + deparseAppendStringInfoString(state, ") "); + + if (create_cast_stmt->func != NULL) + { + deparseAppendStringInfoString(state, "WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_cast_stmt->func); + deparseAppendStringInfoChar(state, ' '); + } + else if (create_cast_stmt->inout) + { + deparseAppendStringInfoString(state, "WITH INOUT "); + } + else + { + deparseAppendStringInfoString(state, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + deparseAppendStringInfoString(state, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + deparseAppendStringInfoString(state, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(DeparseState *state, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE OPERATOR CLASS "); + + deparseAnyName(state, create_op_class_stmt->opclassname); + deparseAppendStringInfoChar(state, ' '); + + if (create_op_class_stmt->isDefault) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, create_op_class_stmt->datatype); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_class_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + deparseAppendStringInfoString(state, "FAMILY "); + deparseAnyName(state, create_op_class_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "AS "); + deparseOpclassItemList(state, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(DeparseState *state, CreateOpFamilyStmt *create_op_family_stmt) +{ + deparseAppendStringInfoString(state, "CREATE OPERATOR FAMILY "); + + deparseAnyName(state, create_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(state, create_op_class_item->name); + else + deparseAnyOperator(state, create_op_class_item->name->objname); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + deparseAppendStringInfoString(state, "FOR ORDER BY "); + deparseAnyName(state, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoChar(state, ')'); + } + removeTrailingSpace(state); + break; + case OPCLASS_ITEM_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoString(state, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(state, create_op_class_item->name); + removeTrailingSpace(state); + break; + case OPCLASS_ITEM_STORAGETYPE: + deparseAppendStringInfoString(state, "STORAGE "); + deparseTypeName(state, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(DeparseState *state, TableLikeClause *table_like_clause) +{ + deparseAppendStringInfoString(state, "LIKE "); + deparseRangeVar(state, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + deparseAppendStringInfoString(state, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + deparseAppendStringInfoString(state, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) + deparseAppendStringInfoString(state, "INCLUDING COMPRESSION "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + deparseAppendStringInfoString(state, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + deparseAppendStringInfoString(state, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + deparseAppendStringInfoString(state, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + deparseAppendStringInfoString(state, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + deparseAppendStringInfoString(state, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + deparseAppendStringInfoString(state, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + deparseAppendStringInfoString(state, "INCLUDING STORAGE "); + } + removeTrailingSpace(state); +} + +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + deparseAppendStringInfoString(state, "CREATE DOMAIN "); + deparseAnyName(state, create_domain_stmt->domainname); + deparseAppendStringInfoString(state, " AS "); + + deparseTypeName(state, create_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(state, create_domain_stmt->collClause); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(state, castNode(Constraint, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseCreateExtensionStmt(DeparseState *state, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseColId(state, create_extension_stmt->extname); + deparseAppendStringInfoChar(state, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + deparseAppendStringInfoString(state, "VERSION "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + deparseAppendStringInfoString(state, "CASCADE"); + } + else + { + Assert(false); + } + + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +// "ColConstraintElem" and "ConstraintElem" in gram.y +static void deparseConstraint(DeparseState *state, Constraint *constraint, DeparseNodeContext context) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(constraint->conname)); + deparseAppendStringInfoChar(state, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + deparseAppendStringInfoString(state, "NULL "); + break; + case CONSTR_NOTNULL: + deparseAppendStringInfoString(state, "NOT NULL "); + break; + case CONSTR_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + deparseBExpr(state, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + deparseAppendStringInfoString(state, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + deparseAppendStringInfoString(state, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + deparseAppendStringInfoString(state, "BY DEFAULT "); + break; + default: + Assert(false); + } + deparseAppendStringInfoString(state, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(state, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + deparseAppendStringInfoString(state, "GENERATED ALWAYS AS ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + if (constraint->generated_kind == ATTRIBUTE_GENERATED_STORED) + deparseAppendStringInfoString(state, "STORED "); + else + deparseAppendStringInfoString(state, "VIRTUAL "); + break; + case CONSTR_CHECK: + deparseAppendStringInfoString(state, "CHECK ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + break; + case CONSTR_PRIMARY: + deparseAppendStringInfoString(state, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + deparseAppendStringInfoString(state, "UNIQUE "); + if (constraint->nulls_not_distinct) + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); + break; + case CONSTR_EXCLUSION: + deparseAppendStringInfoString(state, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(constraint->access_method)); + deparseAppendStringInfoChar(state, ' '); + } + deparseAppendStringInfoChar(state, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(state, castNode(IndexElem, linitial(exclusion))); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyOperator(state, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + if (constraint->where_clause != NULL) + { + deparseAppendStringInfoString(state, "WHERE ("); + deparseExpr(state, constraint->where_clause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + deparseAppendStringInfoString(state, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + deparseAppendStringInfoString(state, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + deparseAppendStringInfoString(state, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + deparseAppendStringInfoString(state, "INITIALLY IMMEDIATE "); + break; + case CONSTR_ATTR_ENFORCED: + deparseAppendStringInfoString(state, "ENFORCED "); + break; + case CONSTR_ATTR_NOT_ENFORCED: + deparseAppendStringInfoString(state, "NOT ENFORCED "); + break; + } + + if (list_length(constraint->keys) > 0) + { + bool emit_keys = true; + bool needs_parens = true; + + if (list_length(constraint->keys) == 1) + { + Node* key = linitial(constraint->keys); + if (context == DEPARSE_NODE_CONTEXT_ALTER_DOMAIN) + emit_keys = !(IsA(key, String) && strcmp(castNode(String, key)->sval, "value") == 0); + needs_parens = constraint->contype != CONSTR_NULL && constraint->contype != CONSTR_NOTNULL; + } + + if (needs_parens) + deparseAppendStringInfoChar(state, '('); + + if (emit_keys) + deparseColumnList(state, constraint->keys); + + if (constraint->without_overlaps) + deparseAppendStringInfoString(state, " WITHOUT OVERLAPS"); + + if (needs_parens) + deparseAppendStringInfoChar(state, ')'); + + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(constraint->fk_attrs) > 0) + { + deparseAppendStringInfoChar(state, '('); + if (constraint->fk_with_period) + deparseColumnListWithPeriod(state, constraint->fk_attrs); + else + deparseColumnList(state, constraint->fk_attrs); + deparseAppendStringInfoString(state, ") "); + } + + if (constraint->pktable != NULL) + { + deparseAppendStringInfoString(state, "REFERENCES "); + deparseRangeVar(state, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + deparseAppendStringInfoChar(state, '('); + if (constraint->pk_with_period) + deparseColumnListWithPeriod(state, constraint->pk_attrs); + else + deparseColumnList(state, constraint->pk_attrs); + deparseAppendStringInfoString(state, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + deparseAppendStringInfoString(state, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + deparseAppendStringInfoString(state, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + deparseAppendStringInfoString(state, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + deparseAppendStringInfoString(state, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + deparseAppendStringInfoString(state, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + deparseAppendStringInfoString(state, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + deparseAppendStringInfoString(state, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + case FKCONSTR_ACTION_SETDEFAULT: + deparseAppendStringInfoString(state, "ON DELETE SET "); + + switch (constraint->fk_del_action) { + case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: deparseAppendStringInfoString(state, "NULL "); break; + } + + if (constraint->fk_del_set_cols) { + deparseAppendStringInfoString(state, "("); + ListCell *lc; + foreach (lc, constraint->fk_del_set_cols) { + deparseAppendStringInfoString(state, strVal(lfirst(lc))); + if (lfirst(lc) != llast(constraint->fk_del_set_cols)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ")"); + } + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + deparseAppendStringInfoString(state, "INCLUDE ("); + deparseColumnList(state, constraint->including); + deparseAppendStringInfoString(state, ") "); + } + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + case CONSTR_UNIQUE: + case CONSTR_EXCLUSION: + deparseOptWith(state, constraint->options); + break; + default: + break; + } + + if (constraint->indexname != NULL) + deparseAppendStringInfo(state, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + deparseAppendStringInfo(state, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + deparseAppendStringInfoString(state, "DEFERRABLE "); + + if (constraint->initdeferred) + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + deparseAppendStringInfoString(state, "NO INHERIT "); + + if ((constraint->contype == CONSTR_FOREIGN || constraint->contype == CONSTR_CHECK) && !constraint->is_enforced) + deparseAppendStringInfoString(state, "NOT ENFORCED "); + + if (constraint->skip_validation) + deparseAppendStringInfoString(state, "NOT VALID "); + + removeTrailingSpace(state); +} + +// "ALTER CONSTRAINT name ConstraintAttributeSpec" in gram.y +static void deparseATAlterConstraint(DeparseState *state, ATAlterConstraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(constraint->conname)); + deparseAppendStringInfoChar(state, ' '); + } + + if (constraint->alterEnforceability) + { + if (constraint->is_enforced) + deparseAppendStringInfoString(state, "ENFORCED "); + else + deparseAppendStringInfoString(state, "NOT ENFORCED "); + } + + if (constraint->alterDeferrability) + { + if (constraint->initdeferred) + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + else if (constraint->deferrable) + deparseAppendStringInfoString(state, "DEFERRABLE "); + else + deparseAppendStringInfoString(state, "NOT DEFERRABLE "); + } + + if (constraint->alterInheritability) + { + if (constraint->noinherit) + deparseAppendStringInfoString(state, "NO INHERIT "); + else + deparseAppendStringInfoString(state, "INHERIT "); + } + + removeTrailingSpace(state); +} + +// "ReturnStmt" in gram.y +static void deparseReturnStmt(DeparseState *state, ReturnStmt *return_stmt) +{ + deparseAppendStringInfoString(state, "RETURN "); + deparseExpr(state, return_stmt->returnval, DEPARSE_NODE_CONTEXT_A_EXPR); +} + +static void deparseCreateFunctionStmt(DeparseState *state, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + deparseAppendStringInfoString(state, "CREATE "); + if (create_function_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + if (create_function_stmt->is_procedure) + deparseAppendStringInfoString(state, "PROCEDURE "); + else + deparseAppendStringInfoString(state, "FUNCTION "); + + deparseFuncName(state, create_function_stmt->funcname); + + deparseAppendStringInfoChar(state, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(state, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + deparseAppendStringInfoString(state, ", "); + } + else + { + tableFunc = true; + } + } + deparseAppendStringInfoString(state, ") "); + + if (tableFunc) + { + deparseAppendStringInfoString(state, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(state, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoString(state, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + deparseAppendStringInfoString(state, "RETURNS "); + deparseTypeName(state, create_function_stmt->returnType); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + { + deparseReturnStmt(state, castNode(ReturnStmt, create_function_stmt->sql_body)); + } + else + { + deparseAppendStringInfoString(state, "BEGIN ATOMIC "); + if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) + { + List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); + foreach(lc, body_stmt_list) + { + if (IsA(lfirst(lc), ReturnStmt)) + { + deparseReturnStmt(state, lfirst_node(ReturnStmt, lc)); + deparseAppendStringInfoString(state, "; "); + } + else + { + deparseStmt(state, lfirst(lc)); + deparseAppendStringInfoString(state, "; "); + } + } + } + + deparseAppendStringInfoString(state, "END "); + } + } + + removeTrailingSpace(state); +} + +// "func_arg", "func_arg_with_default" and other places in gram.y +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + deparseAppendStringInfoString(state, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + deparseAppendStringInfoString(state, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + deparseAppendStringInfoString(state, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + deparseAppendStringInfoString(state, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + deparseAppendStringInfoString(state, function_parameter->name); + deparseAppendStringInfoChar(state, ' '); + } + + deparseTypeName(state, function_parameter->argType); + deparseAppendStringInfoChar(state, ' '); + + if (function_parameter->defexpr != NULL) + { + deparseAppendStringInfoString(state, "= "); + deparseExpr(state, function_parameter->defexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + removeTrailingSpace(state); +} + +static void deparseCheckPointStmt(DeparseState *state, CheckPointStmt *check_point_stmt) +{ + deparseAppendStringInfoString(state, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(DeparseState *state, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + deparseAppendStringInfoString(state, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(state, create_schema_stmt->schemaname); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + deparseAppendStringInfoString(state, "AUTHORIZATION "); + deparseRoleSpec(state, create_schema_stmt->authrole); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(state, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseAlterRoleSetStmt(DeparseState *state, AlterRoleSetStmt *alter_role_set_stmt) +{ + deparseAppendStringInfoString(state, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + deparseAppendStringInfoString(state, "ALL"); + else + deparseRoleSpec(state, alter_role_set_stmt->role); + + deparseAppendStringInfoChar(state, ' '); + + if (alter_role_set_stmt->database != NULL) + { + deparseAppendStringInfoString(state, "IN DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(alter_role_set_stmt->database)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseVariableSetStmt(state, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(DeparseState *state, CreateConversionStmt *create_conversion_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + if (create_conversion_stmt->def) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, create_conversion_stmt->conversion_name); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "FOR "); + deparseStringLiteral(state, create_conversion_stmt->for_encoding_name); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, create_conversion_stmt->to_encoding_name); + + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + deparseAppendStringInfoString(state, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + deparseAppendStringInfoString(state, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + deparseAppendStringInfoString(state, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + deparseAppendStringInfoString(state, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + deparseAppendStringInfoString(state, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(DeparseState *state, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(state, partition_elem->name); + deparseAppendStringInfoChar(state, ' '); + } + else if (partition_elem->expr != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, partition_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + deparseOptCollate(state, partition_elem->collation); + deparseAnyName(state, partition_elem->opclass); + + removeTrailingSpace(state); +} + +static void deparsePartitionSpec(DeparseState *state, PartitionSpec *partition_spec) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "PARTITION BY", DEPARSE_PART_INDENT); + + switch (partition_spec->strategy) + { + case PARTITION_STRATEGY_LIST: + deparseAppendStringInfoString(state, "LIST"); + break; + case PARTITION_STRATEGY_HASH: + deparseAppendStringInfoString(state, "HASH"); + break; + case PARTITION_STRATEGY_RANGE: + deparseAppendStringInfoString(state, "RANGE"); + break; + } + + deparseAppendStringInfoString(state, " ("); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(state, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +static void deparsePartitionBoundSpec(DeparseState *state, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + deparseAppendStringInfoString(state, "DEFAULT"); + return; + } + + deparseAppendStringInfoString(state, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + deparseAppendStringInfo(state, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + deparseAppendStringInfoString(state, "IN ("); + deparseExprList(state, partition_bound_spec->listdatums); + deparseAppendStringInfoChar(state, ')'); + break; + case PARTITION_STRATEGY_RANGE: + deparseAppendStringInfoString(state, "FROM ("); + deparseExprList(state, partition_bound_spec->lowerdatums); + deparseAppendStringInfoString(state, ") TO ("); + deparseExprList(state, partition_bound_spec->upperdatums); + deparseAppendStringInfoChar(state, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(DeparseState *state, PartitionCmd *partition_cmd) +{ + deparseRangeVar(state, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + deparseAppendStringInfoChar(state, ' '); + deparsePartitionBoundSpec(state, partition_cmd->bound); + } + if (partition_cmd->concurrent) + deparseAppendStringInfoString(state, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(state, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(state, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(state, castNode(Constraint, node), DEPARSE_NODE_CONTEXT_NONE); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(DeparseState *state, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (is_foreign_table) + deparseAppendStringInfoString(state, "FOREIGN "); + + deparseOptTemp(state, create_stmt->relation->relpersistence); + + deparseAppendStringInfoString(state, "TABLE "); + + if (create_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseRangeVar(state, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_stmt->ofTypename != NULL) + { + deparseAppendStringInfoString(state, "OF "); + deparseTypeName(state, create_stmt->ofTypename); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + deparseAppendStringInfoString(state, "PARTITION OF "); + deparseRangeVar(state, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + DeparseStateNestingLevel *parent_level = NULL; + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(state, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoString(state, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + deparseAppendStringInfoString(state, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(state, create_stmt->partbound); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseOptInherit(state, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(state, create_stmt->partspec); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(state, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + deparseAppendStringInfoString(state, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(state); +} + +static void deparseCreateFdwStmt(DeparseState *state, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(state, create_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); + } + + deparseCreateGenericOptions(state, create_fdw_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterFdwStmt(DeparseState *state, AlterFdwStmt *alter_fdw_stmt) +{ + deparseAppendStringInfoString(state, "ALTER FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(alter_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(state, alter_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(state, alter_fdw_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateForeignServerStmt(DeparseState *state, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + deparseAppendStringInfoString(state, "TYPE "); + deparseStringLiteral(state, create_foreign_server_stmt->servertype); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + deparseAppendStringInfoString(state, "VERSION "); + deparseStringLiteral(state, create_foreign_server_stmt->version); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, create_foreign_server_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterForeignServerStmt(DeparseState *state, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + deparseAppendStringInfoString(state, "ALTER SERVER "); + + deparseAppendStringInfoString(state, quote_identifier(alter_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (alter_foreign_server_stmt->has_version) + { + deparseAppendStringInfoString(state, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(state, alter_foreign_server_stmt->version); + else + deparseAppendStringInfoString(state, "NULL"); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(state, alter_foreign_server_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateUserMappingStmt(DeparseState *state, CreateUserMappingStmt *create_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, create_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, create_user_mapping_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreatedbStmt(DeparseState *state, CreatedbStmt *createdb_stmt) +{ + deparseAppendStringInfoString(state, "CREATE DATABASE "); + deparseColId(state, createdb_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, createdb_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterUserMappingStmt(DeparseState *state, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "ALTER USER MAPPING FOR "); + deparseRoleSpec(state, alter_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(alter_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + deparseAlterGenericOptions(state, alter_user_mapping_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseDropUserMappingStmt(DeparseState *state, DropUserMappingStmt *drop_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, drop_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(DeparseState *state, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + deparseAppendStringInfoString(state, "FOR "); + deparseAppendStringInfoString(state, quote_identifier(sec_label_stmt->provider)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + deparseAppendStringInfoString(state, "COLUMN "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseValue(state, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(state, sec_label_stmt->label); + else + deparseAppendStringInfoString(state, "NULL"); +} + +static void deparseCreateForeignTableStmt(DeparseState *state, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(state, &create_foreign_table_stmt->base, true); + + deparseAppendStringInfoString(state, " SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_table_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(state, create_foreign_table_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseImportForeignSchemaStmt(DeparseState *state, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + deparseAppendStringInfoString(state, "IMPORT FOREIGN SCHEMA "); + + deparseAppendStringInfoString(state, import_foreign_schema_stmt->remote_schema); + deparseAppendStringInfoChar(state, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + deparseAppendStringInfoString(state, "LIMIT TO ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + deparseAppendStringInfoString(state, "EXCEPT ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); + break; + } + + deparseAppendStringInfoString(state, "FROM SERVER "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->server_name)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "INTO "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->local_schema)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, import_foreign_schema_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateTableAsStmt(DeparseState *state, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + deparseAppendStringInfoString(state, "CREATE "); + + deparseOptTemp(state, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseIntoClause(state, create_table_as_stmt->into); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(state, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(state, castNode(SelectStmt, create_table_as_stmt->query), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_table_as_stmt->into->skipData) + deparseAppendStringInfoString(state, "WITH NO DATA "); + + removeTrailingSpace(state); +} + +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (view_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseOptTemp(state, view_stmt->view->relpersistence); + + deparseAppendStringInfoString(state, "VIEW "); + deparseRangeVar(state, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, view_stmt->aliases); + deparseAppendStringInfoString(state, ") "); + } + + deparseOptWith(state, view_stmt->options); + + deparseAppendStringInfoString(state, "AS "); + deparseSelectStmt(state, castNode(SelectStmt, view_stmt->query), DEPARSE_NODE_CONTEXT_NONE); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + deparseAppendStringInfoString(state, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + deparseAppendStringInfoString(state, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(state); +} + +static void deparseDropStmt(DeparseState *state, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + deparseAppendStringInfoString(state, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(state, strVal(llast(l))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(state, drop_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + deparseAppendStringInfoString(state, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + deparseAppendStringInfoString(state, "ROLLUP ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + case GROUPING_SET_CUBE: + deparseAppendStringInfoString(state, "CUBE ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + case GROUPING_SET_SETS: + deparseAppendStringInfoString(state, "GROUPING SETS ("); + deparseGroupByList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(DeparseState *state, DropTableSpaceStmt *drop_table_space_stmt) +{ + deparseAppendStringInfoString(state, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(DeparseState *state, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + deparseColId(state, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + + if (alter_object_depends_stmt->remove) + deparseAppendStringInfoString(state, "NO "); + + deparseAppendStringInfo(state, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); +} + +static void deparseAlterObjectSchemaStmt(DeparseState *state, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " SET SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(alter_object_schema_stmt->newschema)); +} + +// "alter_table_cmd" in gram.y +static void deparseAlterTableCmd(DeparseState *state, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ADD ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "ADD COLUMN "); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_SetStatistics: /* alter column set statistics */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "DROP ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "DROP "); + break; + case AT_AddIndex: /* add index */ + deparseAppendStringInfoString(state, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + deparseAppendStringInfoString(state, "ADD "); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + deparseAppendStringInfoString(state, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ALTER ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + deparseAppendStringInfoString(state, "OWNER TO "); + deparseRoleSpec(state, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + deparseAppendStringInfoString(state, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + deparseAppendStringInfoString(state, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + deparseAppendStringInfoString(state, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + deparseAppendStringInfoString(state, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + deparseAppendStringInfoString(state, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + deparseAppendStringInfoString(state, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + deparseAppendStringInfoString(state, "SET "); + break; + case AT_SetAccessMethod: + deparseAppendStringInfo(state, "SET ACCESS METHOD "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + deparseAppendStringInfoString(state, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER ALL "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + deparseAppendStringInfoString(state, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + deparseAppendStringInfoString(state, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + deparseAppendStringInfoString(state, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + deparseAppendStringInfoString(state, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + deparseAppendStringInfoString(state, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + deparseAppendStringInfoString(state, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + deparseAppendStringInfoString(state, "OF "); + break; + case AT_DropOf: /* NOT OF */ + deparseAppendStringInfoString(state, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + deparseAppendStringInfoString(state, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + deparseAppendStringInfoString(state, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + deparseAppendStringInfoString(state, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + deparseAppendStringInfoString(state, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + deparseAppendStringInfoString(state, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + deparseAppendStringInfoString(state, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + deparseAppendStringInfoString(state, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + deparseAppendStringInfoString(state, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + deparseAppendStringInfoString(state, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + deparseAppendStringInfoString(state, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + case AT_SetExpression: + deparseAppendStringInfoString(state, "ALTER COLUMN "); + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + else + deparseAppendStringInfoString(state, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(alter_table_cmd->name)); + deparseAppendStringInfoChar(state, ' '); + } else if (alter_table_cmd->subtype == AT_SetAccessMethod) + { + deparseAppendStringInfoString(state, " DEFAULT"); + } + + if (alter_table_cmd->num > 0) + deparseAppendStringInfo(state, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + deparseAppendStringInfoString(state, options); + deparseAppendStringInfoChar(state, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoString(state, " FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(state, castNode(ColumnDef, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + break; + case AT_SetStatistics: + if (alter_table_cmd->def != NULL) + deparseSignedIconst(state, alter_table_cmd->def); + else + deparseAppendStringInfoString(state, "DEFAULT"); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetStorage: + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + deparseAppendStringInfoString(state, "DEFAULT"); + else + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + deparseConstraint(state, castNode(Constraint, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AlterConstraint: + deparseATAlterConstraint(state, castNode(ATAlterConstraint, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(state, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddOf: + deparseTypeName(state, castNode(TypeName, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(state, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetExpression: + deparseAppendStringInfoString(state, "SET EXPRESSION AS ("); + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(state, alter_table_cmd->behavior); + + removeTrailingSpace(state); +} + +static DeparseNodeContext deparseAlterTableObjType(DeparseState *state, ObjectType type) +{ + switch (type) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + return DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + return DEPARSE_NODE_CONTEXT_NONE; +} + +static void deparseAlterTableMoveAllStmt(DeparseState *state, AlterTableMoveAllStmt *move_all_stmt) +{ + deparseAppendStringInfoString(state, "ALTER "); + deparseAlterTableObjType(state, move_all_stmt->objtype); + + deparseAppendStringInfoString(state, "ALL IN TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->orig_tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (move_all_stmt->roles) + { + deparseAppendStringInfoString(state, "OWNED BY "); + deparseRoleList(state, move_all_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "SET TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->new_tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (move_all_stmt->nowait) + { + deparseAppendStringInfoString(state, "NOWAIT"); + } +} + +static void deparseAlterTableStmt(DeparseState *state, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(state, alter_table_stmt->objtype); + + if (alter_table_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRangeVar(state, alter_table_stmt->relation, context); + deparseAppendStringInfoChar(state, ' '); + + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(state, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseAlterTableSpaceOptionsStmt(DeparseState *state, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TABLESPACE "); + deparseColId(state, alter_table_space_options_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (alter_table_space_options_stmt->isReset) + deparseAppendStringInfoString(state, "RESET "); + else + deparseAppendStringInfoString(state, "SET "); + + deparseRelOptions(state, alter_table_space_options_stmt->options); +} + +// "AlterDomainStmt" in gram.y +static void deparseAlterDomainStmt(DeparseState *state, AlterDomainStmt *alter_domain_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DOMAIN "); + deparseAnyName(state, alter_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + deparseAppendStringInfoString(state, "SET DEFAULT "); + deparseExpr(state, alter_domain_stmt->def, DEPARSE_NODE_CONTEXT_A_EXPR); + } + else + { + deparseAppendStringInfoString(state, "DROP DEFAULT"); + } + break; + case 'N': + deparseAppendStringInfoString(state, "DROP NOT NULL"); + break; + case 'O': + deparseAppendStringInfoString(state, "SET NOT NULL"); + break; + case 'C': + deparseAppendStringInfoString(state, "ADD "); + deparseConstraint(state, castNode(Constraint, alter_domain_stmt->def), DEPARSE_NODE_CONTEXT_ALTER_DOMAIN); + break; + case 'X': + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + deparseAppendStringInfoString(state, " CASCADE"); + break; + case 'V': + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(DeparseState *state, RenameStmt *rename_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + deparseAppendStringInfoString(state, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(state, strVal(rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME COLUMN "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, quote_identifier(strVal(rename_stmt->object))); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + deparseAppendStringInfoString(state, " RENAME ATTRIBUTE "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + default: + Assert(false); + break; + } + + deparseAppendStringInfoString(state, "TO "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->newname)); + deparseAppendStringInfoChar(state, ' '); + + deparseOptDropBehavior(state, rename_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseTransactionStmt(DeparseState *state, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + deparseAppendStringInfoString(state, "BEGIN "); + deparseTransactionModeList(state, transaction_stmt->options); + break; + case TRANS_STMT_START: + deparseAppendStringInfoString(state, "START TRANSACTION "); + deparseTransactionModeList(state, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + deparseAppendStringInfoString(state, "COMMIT "); + if (transaction_stmt->chain) + deparseAppendStringInfoString(state, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + deparseAppendStringInfoString(state, "ROLLBACK "); + if (transaction_stmt->chain) + deparseAppendStringInfoString(state, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + deparseAppendStringInfoString(state, "SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + deparseAppendStringInfoString(state, "RELEASE "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + deparseAppendStringInfoString(state, "ROLLBACK "); + deparseAppendStringInfoString(state, "TO SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + deparseAppendStringInfoString(state, "PREPARE TRANSACTION "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + deparseAppendStringInfoString(state, "COMMIT PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + deparseAppendStringInfoString(state, "ROLLBACK PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + } + + removeTrailingSpace(state); +} + +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + if (strcmp(variable_set_stmt->name, "timezone") == 0 && variable_set_stmt->jumble_args) + { + deparseAppendStringInfoString(state, "TIME ZONE "); + deparseVarList(state, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "xmloption") == 0 && variable_set_stmt->jumble_args) + { + char *option = linitial_node(A_Const, variable_set_stmt->args)->val.sval.sval; + deparseAppendStringInfoString(state, "XML OPTION "); + if (strcmp(option, "DOCUMENT") == 0) + deparseAppendStringInfoString(state, "DOCUMENT "); + else if (strcmp(option, "CONTENT") == 0) + deparseAppendStringInfoString(state, "CONTENT "); + else + deparseVarList(state, variable_set_stmt->args); + } + else + { + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO "); + deparseVarList(state, variable_set_stmt->args); + } + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + if (strcmp(variable_set_stmt->name, "timezone") == 0 && variable_set_stmt->jumble_args) + { + deparseAppendStringInfoString(state, "TIME ZONE DEFAULT"); + } + else + { + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO DEFAULT"); + } + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + deparseAppendStringInfoString(state, "TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + deparseAppendStringInfoString(state, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + deparseAppendStringInfoString(state, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(state, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + deparseAppendStringInfoString(state, "RESET "); + deparseVarName(state, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + deparseAppendStringInfoString(state, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(DeparseState *state, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, quote_identifier(dropdb_stmt->dbname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + deparseAppendStringInfoString(state, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseVacuumStmt(DeparseState *state, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + deparseAppendStringInfoString(state, "VACUUM "); + else + deparseAppendStringInfoString(state, "ANALYZE "); + + deparseUtilityOptionList(state, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(state, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc2, rel->va_cols) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + deparseAppendStringInfoString(state, ", "); + } + + removeTrailingSpace(state); +} + +static void deparseLoadStmt(DeparseState *state, LoadStmt *load_stmt) +{ + deparseAppendStringInfoString(state, "LOAD "); + deparseStringLiteral(state, load_stmt->filename); +} + +static void deparseLockStmt(DeparseState *state, LockStmt *lock_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "LOCK TABLE "); + + deparseRelationExprList(state, lock_stmt->relations); + deparseAppendStringInfoChar(state, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + deparseAppendStringInfoString(state, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + deparseAppendStringInfoString(state, "ACCESS SHARE "); + break; + case RowShareLock: + deparseAppendStringInfoString(state, "ROW SHARE "); + break; + case RowExclusiveLock: + deparseAppendStringInfoString(state, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + deparseAppendStringInfoString(state, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + deparseAppendStringInfoString(state, "SHARE "); + break; + case ShareRowExclusiveLock: + deparseAppendStringInfoString(state, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + deparseAppendStringInfoString(state, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + deparseAppendStringInfoString(state, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + deparseAppendStringInfoString(state, "MODE "); + } + + if (lock_stmt->nowait) + deparseAppendStringInfoString(state, "NOWAIT "); + + removeTrailingSpace(state); +} + +static void deparseConstraintsSetStmt(DeparseState *state, ConstraintsSetStmt *constraints_set_stmt) +{ + deparseAppendStringInfoString(state, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(state, constraints_set_stmt->constraints); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "ALL "); + } + + if (constraints_set_stmt->deferred) + deparseAppendStringInfoString(state, "DEFERRED"); + else + deparseAppendStringInfoString(state, "IMMEDIATE"); +} + +static void deparseExplainStmt(DeparseState *state, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + deparseAppendPartGroup(state, "EXPLAIN", DEPARSE_PART_NO_INDENT); + + deparseUtilityOptionList(state, explain_stmt->options); + + deparseExplainableStmt(state, explain_stmt->query); +} + +static void deparseCopyStmt(DeparseState *state, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + deparseAppendPartGroup(state, "COPY", DEPARSE_PART_INDENT); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(state, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, copy_stmt->attlist); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + } + + if (copy_stmt->query != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, copy_stmt->query); + deparseAppendStringInfoString(state, ") "); + } + + if (copy_stmt->is_from) + deparseAppendStringInfoString(state, "FROM "); + else + deparseAppendStringInfoString(state, "TO "); + + if (copy_stmt->is_program) + deparseAppendStringInfoString(state, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(state, copy_stmt->filename); + deparseAppendStringInfoChar(state, ' '); + } + else + { + if (copy_stmt->is_from) + deparseAppendStringInfoString(state, "STDIN "); + else + deparseAppendStringInfoString(state, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + // In some cases, equivalent expressions may have slightly different parse trees for `COPY` + // statements. For example the following two statements result in different (but equivalent) parse + // trees: + // + // - COPY foo FROM STDIN CSV FREEZE + // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) + // + // In order to make sure we deparse to the "correct" version, we always try to deparse to the older + // compact syntax first. + // + // The old syntax can be seen here in the Postgres 8.4 Reference: + // https://www.postgresql.org/docs/8.4/sql-copy.html + + bool old_fmt = true; + + // Loop over the options to see if any require the new `WITH (...)` syntax. + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + {} + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + {} + else + { + old_fmt = false; + break; + } + } + + // Branch to differing output modes, depending on if we can use the old syntax. + if (old_fmt) { + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + deparseAppendStringInfoString(state, "FREEZE "); + } + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + deparseAppendStringInfoString(state, "HEADER "); + } + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + { + deparseAppendStringInfoString(state, "CSV "); + } + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + { + deparseAppendStringInfoString(state, "FORCE QUOTE "); + deparseColumnList(state, castNode(List, def_elem->arg)); + } + else + { + // This isn't reachable, the conditions here are exactly the same as the first loop above. + Assert(false); + } + } + } else { + deparseAppendStringInfoString(state, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + deparseAppendStringInfoString(state, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + deparseAppendStringInfoString(state, "BINARY"); + else if (strcmp(format, "csv") == 0) + deparseAppendStringInfoString(state, "CSV"); + else if (strcmp(format, "text") == 0) + deparseAppendStringInfoString(state, "TEXT"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0) + { + deparseAppendStringInfoString(state, "FREEZE"); + deparseOptBoolean(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + deparseAppendStringInfoString(state, "DELIMITER "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + deparseAppendStringInfoString(state, "NULL "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0) + { + deparseAppendStringInfoString(state, "HEADER"); + deparseOptBoolean(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + deparseAppendStringInfoString(state, "QUOTE "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + deparseAppendStringInfoString(state, "ESCAPE "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + deparseAppendStringInfoString(state, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + deparseAppendStringInfoChar(state, '*'); + } + else if (IsA(def_elem->arg, List)) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + deparseAppendStringInfoString(state, "FORCE_NOT_NULL "); + + if (IsA(def_elem->arg, A_Star)) + deparseAStar(state, castNode(A_Star, def_elem->arg)); + else + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + deparseAppendStringInfoString(state, "FORCE_NULL "); + + if (IsA(def_elem->arg, A_Star)) + deparseAStar(state, castNode(A_Star, def_elem->arg)); + else + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + deparseAppendStringInfoString(state, "ENCODING "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else + { + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + deparseAppendStringInfoChar(state, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(state, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoChar(state, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(state, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + } + + deparseWhereClause(state, copy_stmt->whereClause); + + removeTrailingSpace(state); +} + +static void deparseDoStmt(DeparseState *state, DoStmt *do_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(defel->arg))); + deparseAppendStringInfoChar(state, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseDiscardStmt(DeparseState *state, DiscardStmt *discard_stmt) +{ + deparseAppendStringInfoString(state, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + deparseAppendStringInfoString(state, "ALL"); + break; + case DISCARD_PLANS: + deparseAppendStringInfoString(state, "PLANS"); + break; + case DISCARD_SEQUENCES: + deparseAppendStringInfoString(state, "SEQUENCES"); + break; + case DISCARD_TEMP: + deparseAppendStringInfoString(state, "TEMP"); + break; + } +} + +static void deparseDefineStmt(DeparseState *state, DefineStmt *define_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (define_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(state, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(state, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(state, define_stmt->defnames); + break; + default: + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(state, define_stmt->args); + deparseAppendStringInfoChar(state, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(state, define_stmt->definition); + } + + removeTrailingSpace(state); +} + +static void deparseCompositeTypeStmt(DeparseState *state, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseRangeVar(state, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + deparseAppendStringInfoString(state, " AS ("); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateEnumStmt(DeparseState *state, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CREATE TYPE "); + + deparseAnyName(state, create_enum_stmt->typeName); + deparseAppendStringInfoString(state, " AS ENUM ("); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(state, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateRangeStmt(DeparseState *state, CreateRangeStmt *create_range_stmt) +{ + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseAnyName(state, create_range_stmt->typeName); + deparseAppendStringInfoString(state, " AS RANGE "); + deparseDefinition(state, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(DeparseState *state, AlterEnumStmt *alter_enum_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_enum_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + deparseAppendStringInfoString(state, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseStringLiteral(state, alter_enum_stmt->newVal); + deparseAppendStringInfoChar(state, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + deparseAppendStringInfoString(state, "AFTER "); + else + deparseAppendStringInfoString(state, "BEFORE "); + deparseStringLiteral(state, alter_enum_stmt->newValNeighbor); + } + } + else + { + deparseAppendStringInfoString(state, "RENAME VALUE "); + deparseStringLiteral(state, alter_enum_stmt->oldVal); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, alter_enum_stmt->newVal); + } + + removeTrailingSpace(state); +} + +static void deparseAlterExtensionStmt(DeparseState *state, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_stmt->extname); + deparseAppendStringInfoString(state, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + deparseAppendStringInfoString(state, "TO "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + } + removeTrailingSpace(state); +} + +static void deparseAlterExtensionContentsStmt(DeparseState *state, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_contents_stmt->extname); + deparseAppendStringInfoChar(state, ' '); + + if (alter_extension_contents_stmt->action == 1) + deparseAppendStringInfoString(state, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + deparseAppendStringInfoString(state, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(state, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(state, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(state, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(DeparseState *state, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + deparseAppendStringInfoString(state, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + deparseAppendStringInfoString(state, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + deparseAppendStringInfoString(state, "create"); + else + deparseAppendStringInfoString(state, quote_identifier(access_priv->priv_name)); + } + else + { + deparseAppendStringInfoString(state, "ALL"); + } + deparseAppendStringInfoChar(state, ' '); + + if (list_length(access_priv->cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, access_priv->cols); + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseGrantStmt(DeparseState *state, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + deparseAppendStringInfoString(state, "GRANT "); + else + deparseAppendStringInfoString(state, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + deparseAppendStringInfoString(state, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "ALL "); + } + + deparseAppendStringInfoString(state, "ON "); + + deparsePrivilegeTarget(state, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + + if (grant_stmt->is_grant) + deparseAppendStringInfoString(state, "TO "); + else + deparseAppendStringInfoString(state, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(state, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + deparseAppendStringInfoString(state, "WITH GRANT OPTION "); + + deparseOptDropBehavior(state, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(state); +} + +static void deparseGrantRoleStmt(DeparseState *state, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + deparseAppendStringInfoString(state, "GRANT "); + else + deparseAppendStringInfoString(state, "REVOKE "); + + if (!grant_role_stmt->is_grant && list_length(grant_role_stmt->opt)) { + DefElem *defelem = castNode(DefElem, linitial(grant_role_stmt->opt)); + Assert(!castNode(Boolean, defelem->arg)->boolval); + + if (strcmp("admin", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "ADMIN "); + } else if (strcmp("inherit", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "INHERIT "); + } else if (strcmp("set", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "SET "); + } + + deparseAppendStringInfoString(state, "OPTION FOR "); + } + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); + } + + if (grant_role_stmt->is_grant) + deparseAppendStringInfoString(state, "TO "); + else + deparseAppendStringInfoString(state, "FROM "); + + deparseRoleList(state, grant_role_stmt->grantee_roles); + deparseAppendStringInfoChar(state, ' '); + + if (grant_role_stmt->is_grant) { + if (list_length(grant_role_stmt->opt) > 0) { + deparseAppendStringInfoString(state, "WITH "); + } + + foreach(lc, grant_role_stmt->opt) { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp("admin", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "ADMIN "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("inherit", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "INHERIT "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("set", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } + + if (lnext(grant_role_stmt->opt, lc)) { + deparseAppendStringInfoChar(state, ','); + } + + deparseAppendStringInfoChar(state, ' '); + } + } + + if (grant_role_stmt->grantor) + { + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + if (grant_role_stmt->behavior == DROP_CASCADE) { + deparseAppendStringInfoString(state, "CASCADE "); + } + + removeTrailingSpace(state); +} + +static void deparseDropRoleStmt(DeparseState *state, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRoleList(state, drop_role_stmt->roles); +} + +static void deparseIndexStmt(DeparseState *state, IndexStmt *index_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (index_stmt->unique) + deparseAppendStringInfoString(state, "UNIQUE "); + + deparseAppendStringInfoString(state, "INDEX "); + + if (index_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(index_stmt->idxname)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "ON", DEPARSE_PART_INDENT); + deparseRangeVar(state, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (index_stmt->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->accessMethod)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoChar(state, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + deparseAppendStringInfoString(state, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + + if (index_stmt->nulls_not_distinct) + { + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); + } + + deparseOptWith(state, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->tableSpace)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, index_stmt->whereClause); + + removeTrailingSpace(state); +} + +static void deparseAlterOpFamilyStmt(DeparseState *state, AlterOpFamilyStmt *alter_op_family_stmt) +{ + deparseAppendStringInfoString(state, "ALTER OPERATOR FAMILY "); + deparseAnyName(state, alter_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(alter_op_family_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + if (alter_op_family_stmt->isDrop) + deparseAppendStringInfoString(state, "DROP "); + else + deparseAppendStringInfoString(state, "ADD "); + + deparseOpclassItemList(state, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(DeparseState *state, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "PREPARE "); + deparseColId(state, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, prepare_stmt->argtypes); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoString(state, " AS "); + deparsePreparableStmt(state, prepare_stmt->query); +} + +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "EXECUTE "); + deparseAppendStringInfoString(state, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, execute_stmt->params); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseDeallocateStmt(DeparseState *state, DeallocateStmt *deallocate_stmt) +{ + deparseAppendStringInfoString(state, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + deparseAppendStringInfoString(state, quote_identifier(deallocate_stmt->name)); + else + deparseAppendStringInfoString(state, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + deparseAppendStringInfoString(state, "PASSWORD "); + if (def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(state, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + deparseAppendStringInfo(state, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + deparseAppendStringInfoString(state, "VALID UNTIL "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + deparseAppendStringInfo(state, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + deparseAppendStringInfoString(state, "ADMIN "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + deparseAppendStringInfoString(state, "IN ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(state, def_elem); + } +} + +static void deparseCreatePLangStmt(DeparseState *state, CreatePLangStmt *create_p_lang_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + + if (create_p_lang_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + deparseAppendStringInfoString(state, "TRUSTED "); + + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, create_p_lang_stmt->plname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_p_lang_stmt->plhandler); + deparseAppendStringInfoChar(state, ' '); + + if (create_p_lang_stmt->plinline) + { + deparseAppendStringInfoString(state, "INLINE "); + deparseHandlerName(state, create_p_lang_stmt->plinline); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, create_p_lang_stmt->plvalidator); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseCreateRoleStmt(DeparseState *state, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case ROLESTMT_USER: + deparseAppendStringInfoString(state, "USER "); + break; + case ROLESTMT_GROUP: + deparseAppendStringInfoString(state, "GROUP "); + break; + } + + deparseAppendStringInfoString(state, quote_identifier(create_role_stmt->role)); + deparseAppendStringInfoChar(state, ' '); + + if (create_role_stmt->options != NULL) + { + deparseAppendStringInfoString(state, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseAlterRoleStmt(DeparseState *state, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + deparseAppendStringInfoString(state, "GROUP "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); + + if (alter_role_stmt->action == 1) + { + deparseAppendStringInfoString(state, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + deparseAppendStringInfoString(state, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(state, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseDeclareCursorStmt(DeparseState *state, DeclareCursorStmt *declare_cursor_stmt) +{ + deparseAppendStringInfoString(state, "DECLARE "); + deparseAppendStringInfoString(state, quote_identifier(declare_cursor_stmt->portalname)); + deparseAppendStringInfoChar(state, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + deparseAppendStringInfoString(state, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + deparseAppendStringInfoString(state, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + deparseAppendStringInfoString(state, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + deparseAppendStringInfoString(state, "INSENSITIVE "); + + deparseAppendStringInfoString(state, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + deparseAppendStringInfoString(state, "WITH HOLD "); + + deparseAppendStringInfoString(state, "FOR "); + + deparseSelectStmt(state, castNode(SelectStmt, declare_cursor_stmt->query), DEPARSE_NODE_CONTEXT_NONE); +} + +static void deparseFetchStmt(DeparseState *state, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + deparseAppendStringInfoString(state, "MOVE "); + else + deparseAppendStringInfoString(state, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + deparseAppendStringInfoString(state, "ALL "); + } + else + { + deparseAppendStringInfo(state, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + deparseAppendStringInfoString(state, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + deparseAppendStringInfoString(state, "BACKWARD ALL "); + } + else + { + deparseAppendStringInfo(state, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + deparseAppendStringInfoString(state, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + deparseAppendStringInfoString(state, "LAST "); + } + else + { + deparseAppendStringInfo(state, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + deparseAppendStringInfo(state, "RELATIVE %ld ", fetch_stmt->howMany); + } + + deparseAppendStringInfoString(state, quote_identifier(fetch_stmt->portalname)); +} + +static void deparseAlterDefaultPrivilegesStmt(DeparseState *state, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + deparseAppendStringInfoString(state, "IN SCHEMA "); + deparseNameList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + deparseAppendStringInfoString(state, "FOR ROLE "); + deparseRoleList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(state, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(DeparseState *state, ReindexStmt *reindex_stmt) +{ + deparseAppendStringInfoString(state, "REINDEX "); + + deparseUtilityOptionList(state, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + deparseAppendStringInfoString(state, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(state, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(DeparseState *state, RuleStmt* rule_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (rule_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseAppendStringInfoString(state, "RULE "); + deparseAppendStringInfoString(state, quote_identifier(rule_stmt->rulename)); + deparseAppendStringInfoString(state, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + deparseAppendStringInfoString(state, "SELECT "); + break; + case CMD_UPDATE: + deparseAppendStringInfoString(state, "UPDATE "); + break; + case CMD_INSERT: + deparseAppendStringInfoString(state, "INSERT "); + break; + case CMD_DELETE: + deparseAppendStringInfoString(state, "DELETE "); + break; + case CMD_MERGE: + deparseAppendStringInfoString(state, "MERGE "); + break; + } + + deparseAppendStringInfoString(state, "TO "); + deparseRangeVar(state, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseWhereClause(state, rule_stmt->whereClause); + + deparseAppendStringInfoString(state, "DO "); + + if (rule_stmt->instead) + deparseAppendStringInfoString(state, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + deparseAppendStringInfoString(state, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(state, linitial(rule_stmt->actions)); + } + else + { + deparseAppendStringInfoChar(state, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(state, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + deparseAppendStringInfoString(state, "; "); + } + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseNotifyStmt(DeparseState *state, NotifyStmt *notify_stmt) +{ + deparseAppendStringInfoString(state, "NOTIFY "); + deparseAppendStringInfoString(state, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseStringLiteral(state, notify_stmt->payload); + } +} + +static void deparseListenStmt(DeparseState *state, ListenStmt *listen_stmt) +{ + deparseAppendStringInfoString(state, "LISTEN "); + deparseAppendStringInfoString(state, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(DeparseState *state, UnlistenStmt *unlisten_stmt) +{ + deparseAppendStringInfoString(state, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + deparseAppendStringInfoString(state, "*"); + else + deparseAppendStringInfoString(state, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(DeparseState *state, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + deparseOptTemp(state, create_seq_stmt->sequence->relpersistence); + + deparseAppendStringInfoString(state, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseRangeVar(state, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseOptSeqOptList(state, create_seq_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterFunctionStmt(DeparseState *state, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(state, alter_function_stmt->func); + deparseAppendStringInfoChar(state, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(state, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +static void deparseTruncateStmt(DeparseState *state, TruncateStmt *truncate_stmt) +{ + deparseAppendStringInfoString(state, "TRUNCATE "); + + deparseRelationExprList(state, truncate_stmt->relations); + deparseAppendStringInfoChar(state, ' '); + + if (truncate_stmt->restart_seqs) + deparseAppendStringInfoString(state, "RESTART IDENTITY "); + + deparseOptDropBehavior(state, truncate_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseCreateEventTrigStmt(DeparseState *state, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + deparseAppendStringInfoString(state, "CREATE EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "ON "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->eventname)); + deparseAppendStringInfoChar(state, ' '); + + if (create_event_trig_stmt->whenclause) + { + deparseAppendStringInfoString(state, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(state, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + deparseAppendStringInfoString(state, " AND "); + } + + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_event_trig_stmt->funcname); + deparseAppendStringInfoString(state, "()"); +} + +static void deparseAlterEventTrigStmt(DeparseState *state, AlterEventTrigStmt *alter_event_trig_stmt) +{ + deparseAppendStringInfoString(state, "ALTER EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(alter_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + deparseAppendStringInfoString(state, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + deparseAppendStringInfoString(state, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + deparseAppendStringInfoString(state, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + deparseAppendStringInfoString(state, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(DeparseState *state, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + deparseAppendStringInfoString(state, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + deparseRangeVar(state, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (refresh_mat_view_stmt->skipData) + deparseAppendStringInfoString(state, "WITH NO DATA "); + + removeTrailingSpace(state); +} + +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + deparseAppendStringInfoString(state, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + deparseAppendStringInfoString(state, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + deparseAppendStringInfoString(state, "USING INDEX "); + deparseAppendStringInfoString(state, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +// "CreatePolicyStmt" in gram.y +static void deparseCreatePolicyStmt(DeparseState *state, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE POLICY "); + deparseColId(state, create_policy_stmt->policy_name); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (!create_policy_stmt->permissive) + deparseAppendStringInfoString(state, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + deparseAppendStringInfoString(state, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + deparseAppendStringInfoString(state, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + deparseAppendStringInfoString(state, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + deparseAppendStringInfoString(state, "FOR DELETE "); + else + Assert(false); + + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, create_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + + if (create_policy_stmt->qual != NULL) + { + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, create_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, create_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } +} + +// "AlterPolicyStmt" in gram.y +static void deparseAlterPolicyStmt(DeparseState *state, AlterPolicyStmt *alter_policy_stmt) +{ + deparseAppendStringInfoString(state, "ALTER POLICY "); + deparseAppendStringInfoString(state, quote_identifier(alter_policy_stmt->policy_name)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, alter_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, alter_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, alter_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } +} + +static void deparseCreateTableSpaceStmt(DeparseState *state, CreateTableSpaceStmt *create_table_space_stmt) +{ + deparseAppendStringInfoString(state, "CREATE TABLESPACE "); + deparseColId(state, create_table_space_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (create_table_space_stmt->owner != NULL) + { + deparseAppendStringInfoString(state, "OWNER "); + deparseRoleSpec(state, create_table_space_stmt->owner); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "LOCATION "); + + if (create_table_space_stmt->location != NULL) + deparseStringLiteral(state, create_table_space_stmt->location); + else + deparseAppendStringInfoString(state, "''"); + + deparseAppendStringInfoChar(state, ' '); + + deparseOptWith(state, create_table_space_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateTransformStmt(DeparseState *state, CreateTransformStmt *create_transform_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + if (create_transform_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseAppendStringInfoString(state, "TRANSFORM FOR "); + deparseTypeName(state, create_transform_stmt->type_name); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(create_transform_stmt->lang)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoChar(state, '('); + + if (create_transform_stmt->fromsql) + { + deparseAppendStringInfoString(state, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + deparseAppendStringInfoString(state, ", "); + + if (create_transform_stmt->tosql) + { + deparseAppendStringInfoString(state, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->tosql); + } + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateAmStmt(DeparseState *state, CreateAmStmt *create_am_stmt) +{ + deparseAppendStringInfoString(state, "CREATE ACCESS METHOD "); + deparseAppendStringInfoString(state, quote_identifier(create_am_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case AMTYPE_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + } + + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_am_stmt->handler_name); +} + +// "pub_obj_list" in gram.y +static void deparsePublicationObjectList(DeparseState *state, List *pubobjects) { + const ListCell *lc; + foreach(lc, pubobjects) { + PublicationObjSpec *obj = lfirst(lc); + + switch (obj->pubobjtype) { + case PUBLICATIONOBJ_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + deparseRangeVar(state, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + + if (obj->pubtable->columns) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, obj->pubtable->columns); + deparseAppendStringInfoChar(state, ')'); + } + + if (obj->pubtable->whereClause) + { + deparseAppendStringInfoString(state, " WHERE ("); + deparseExpr(state, obj->pubtable->whereClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); + } + + break; + case PUBLICATIONOBJ_TABLES_IN_SCHEMA: + deparseAppendStringInfoString(state, "TABLES IN SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(obj->name)); + break; + case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: + deparseAppendStringInfoString(state, "TABLES IN SCHEMA CURRENT_SCHEMA"); + break; + case PUBLICATIONOBJ_CONTINUATION: + // This should be unreachable, the parser merges these before we can even get here. + Assert(false); + break; + } + + if (lnext(pubobjects, lc)) { + deparseAppendStringInfoString(state, ", "); + } + } +} + +static void deparseCreatePublicationStmt(DeparseState *state, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(create_publication_stmt->pubname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_publication_stmt->pubobjects) > 0) + { + deparseAppendStringInfoString(state, "FOR "); + deparsePublicationObjectList(state, create_publication_stmt->pubobjects); + deparseAppendStringInfoChar(state, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + deparseAppendStringInfoString(state, "FOR ALL TABLES "); + } + + deparseOptDefinition(state, create_publication_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterPublicationStmt(DeparseState *state, AlterPublicationStmt *alter_publication_stmt) +{ + deparseAppendStringInfoString(state, "ALTER PUBLICATION "); + deparseColId(state, alter_publication_stmt->pubname); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_publication_stmt->pubobjects) > 0) + { + switch (alter_publication_stmt->action) + { + case AP_SetObjects: + deparseAppendStringInfoString(state, "SET "); + break; + case AP_AddObjects: + deparseAppendStringInfoString(state, "ADD "); + break; + case AP_DropObjects: + deparseAppendStringInfoString(state, "DROP "); + break; + } + + deparsePublicationObjectList(state, alter_publication_stmt->pubobjects); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(DeparseState *state, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRangeVar(state, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseSeqOptList(state, alter_seq_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterSystemStmt(DeparseState *state, AlterSystemStmt *alter_system_stmt) +{ + deparseAppendStringInfoString(state, "ALTER SYSTEM "); + deparseVariableSetStmt(state, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(DeparseState *state, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + deparseAppendStringInfoString(state, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + deparseAppendStringInfoString(state, "COLUMN "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + deparseAppendStringInfoString(state, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAppendStringInfoString(state, "CONSTRAINT "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(state, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(state, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON DOMAIN "); + deparseTypeName(state, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(state, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(state, comment_stmt->comment); + else + deparseAppendStringInfoString(state, "NULL"); +} + +// "stats_param" in gram.y +static void deparseStatsElem(DeparseState *state, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + deparseAppendStringInfoString(state, stats_elem->name); + else if (stats_elem->expr) + { + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, stats_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseCreateStatsStmt(DeparseState *state, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseAnyName(state, create_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, create_stats_stmt->stat_types); + deparseAppendStringInfoString(state, ") "); + } + + deparseAppendStringInfoString(state, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(state, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoString(state, " FROM "); + deparseFromList(state, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(DeparseState *state, AlterCollationStmt *alter_collation_stmt) +{ + deparseAppendStringInfoString(state, "ALTER COLLATION "); + deparseAnyName(state, alter_collation_stmt->collname); + deparseAppendStringInfoString(state, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(DeparseState *state, AlterDatabaseStmt *alter_database_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, alter_database_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterDatabaseSetStmt(DeparseState *state, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_set_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseVariableSetStmt(state, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(DeparseState *state, AlterStatsStmt *alter_stats_stmt) +{ + deparseAppendStringInfoString(state, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAnyName(state, alter_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); + + if (alter_stats_stmt->stxstattarget) + deparseAppendStringInfo(state, "SET STATISTICS %d", castNode(Integer, alter_stats_stmt->stxstattarget)->ival); + else + deparseAppendStringInfo(state, "SET STATISTICS DEFAULT"); +} + +static void deparseAlterTSDictionaryStmt(DeparseState *state, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(state, alter_ts_dictionary_stmt->dictname); + deparseAppendStringInfoChar(state, ' '); + + deparseDefinition(state, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(DeparseState *state, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, alter_ts_configuration_stmt->cfgname); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + deparseAppendStringInfoString(state, "ADD MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + deparseAppendStringInfoString(state, "ALTER MAPPING REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + deparseAppendStringInfoString(state, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, "FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(DeparseState *state, VariableShowStmt *variable_show_stmt) +{ + deparseAppendStringInfoString(state, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + deparseAppendStringInfoString(state, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + deparseAppendStringInfoString(state, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + deparseAppendStringInfoString(state, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + deparseAppendStringInfoString(state, "ALL"); + else + deparseAppendStringInfoString(state, quote_identifier(variable_show_stmt->name)); +} + +// "tablesample_clause" in gram.y +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample) +{ + deparseRangeVar(state, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + deparseAppendStringInfoString(state, " TABLESAMPLE "); + + deparseFuncName(state, range_table_sample->method); + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, range_table_sample->args); + deparseAppendStringInfoString(state, ") "); + + if (range_table_sample->repeatable != NULL) + { + deparseAppendStringInfoString(state, "REPEATABLE ("); + deparseExpr(state, range_table_sample->repeatable, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + removeTrailingSpace(state); +} + +static void deparseCreateSubscriptionStmt(DeparseState *state, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(create_subscription_stmt->subname)); + + deparseAppendStringInfoString(state, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(state, create_subscription_stmt->conninfo); + else + deparseAppendStringInfoString(state, "''"); + + deparseAppendStringInfoString(state, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + + deparseOptDefinition(state, create_subscription_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterSubscriptionStmt(DeparseState *state, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(alter_subscription_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SKIP: + deparseAppendStringInfoString(state, "SKIP "); + deparseDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + deparseAppendStringInfoString(state, "CONNECTION "); + deparseStringLiteral(state, alter_subscription_stmt->conninfo); + deparseAppendStringInfoChar(state, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + deparseAppendStringInfoString(state, "REFRESH PUBLICATION "); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + deparseAppendStringInfoString(state, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + deparseAppendStringInfoString(state, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + deparseAppendStringInfoString(state, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (optBooleanValue(defelem->arg)) + { + deparseAppendStringInfoString(state, " ENABLE "); + } + else + { + deparseAppendStringInfoString(state, " DISABLE "); + } + break; + } + + removeTrailingSpace(state); +} + +static void deparseDropSubscriptionStmt(DeparseState *state, DropSubscriptionStmt *drop_subscription_stmt) +{ + deparseAppendStringInfoString(state, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(DeparseState *state, CallStmt *call_stmt) +{ + deparseAppendStringInfoString(state, "CALL "); + deparseFuncCall(state, call_stmt->funccall, DEPARSE_NODE_CONTEXT_NONE); +} + +static void deparseAlterOwnerStmt(DeparseState *state, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnly(state, (union ValUnion *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + deparseAppendStringInfoString(state, " OWNER TO "); + deparseRoleSpec(state, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(DeparseState *state, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " = "); + if (def_elem->arg != NULL) + deparseDefArg(state, def_elem->arg, true); + else + deparseAppendStringInfoString(state, "NONE"); + + if (lnext(defs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +static void deparseAlterOperatorStmt(DeparseState *state, AlterOperatorStmt *alter_operator_stmt) +{ + deparseAppendStringInfoString(state, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(state, alter_operator_stmt->opername); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_operator_stmt->options); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseAlterTypeStmt(DeparseState *state, AlterTypeStmt *alter_type_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_type_stmt->typeName); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_type_stmt->options); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseDropOwnedStmt(DeparseState *state, DropOwnedStmt *drop_owned_stmt) +{ + deparseAppendStringInfoString(state, "DROP OWNED BY "); + deparseRoleList(state, drop_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + deparseOptDropBehavior(state, drop_owned_stmt->behavior); + removeTrailingSpace(state); +} + +static void deparseReassignOwnedStmt(DeparseState *state, ReassignOwnedStmt *reassigned_owned_stmt) +{ + deparseAppendStringInfoString(state, "REASSIGN OWNED BY "); + + deparseRoleList(state, reassigned_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "TO "); + deparseRoleSpec(state, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(DeparseState *state, ClosePortalStmt *close_portal_stmt) +{ + deparseAppendStringInfoString(state, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(close_portal_stmt->portalname)); + } + else + { + deparseAppendStringInfoString(state, "ALL"); + } +} + +// "CreateTrigStmt" in gram.y +static void deparseCreateTrigStmt(DeparseState *state, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + deparseAppendStringInfoString(state, "CREATE "); + if (create_trig_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, "TRIGGER "); + + deparseAppendStringInfoString(state, quote_identifier(create_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + deparseAppendStringInfoString(state, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + deparseAppendStringInfoString(state, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + deparseAppendStringInfoString(state, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + deparseAppendStringInfoString(state, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + deparseAppendStringInfoString(state, "OF "); + deparseColumnList(state, create_trig_stmt->columns); + deparseAppendStringInfoChar(state, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "TRUNCATE "); + } + + deparseAppendStringInfoString(state, "ON "); + deparseRangeVar(state, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + deparseAppendStringInfoString(state, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(state, castNode(TriggerTransition, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_trig_stmt->deferrable) + deparseAppendStringInfoString(state, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + deparseAppendStringInfoString(state, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + deparseAppendStringInfoString(state, "WHEN ("); + deparseExpr(state, create_trig_stmt->whenClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_trig_stmt->funcname); + deparseAppendStringInfoChar(state, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(state, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + deparseAppendStringInfoString(state, "NEW "); + else + deparseAppendStringInfoString(state, "OLD "); + + if (trigger_transition->isTable) + deparseAppendStringInfoString(state, "TABLE "); + else + deparseAppendStringInfoString(state, "ROW "); + + deparseAppendStringInfoString(state, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + deparseAppendStringInfoString(state, "xmlconcat("); + deparseExprList(state, xml_expr->args); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + deparseAppendStringInfoString(state, "xmlelement(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + deparseAppendStringInfoString(state, ", xmlattributes("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoString(state, ")"); + } + if (xml_expr->args != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseExprList(state, xml_expr->args); + } + deparseAppendStringInfoString(state, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + deparseAppendStringInfoString(state, "xmlforest("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + deparseAppendStringInfoString(state, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + deparseAppendStringInfoString(state, "document "); + break; + case XMLOPTION_CONTENT: + deparseAppendStringInfoString(state, "content "); + break; + default: + Assert(false); + } + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + deparseAppendStringInfoString(state, "xmlpi(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + deparseAppendStringInfoString(state, "xmlroot("); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", version "); + if (castNode(A_Const, lsecond(xml_expr->args))->isnull) + deparseAppendStringInfoString(state, "no value"); + else + deparseExpr(state, lsecond(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + deparseAppendStringInfoString(state, ", standalone yes"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + deparseAppendStringInfoString(state, ", standalone no"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + deparseAppendStringInfoString(state, ", standalone no value"); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(state, linitial(xml_expr->args), context); + deparseAppendStringInfoString(state, " IS DOCUMENT"); + break; + } +} + +// "xmltable_column_el" in gram.y +static void deparseRangeTableFuncCol(DeparseState *state, RangeTableFuncCol* range_table_func_col) +{ + deparseAppendStringInfoString(state, quote_identifier(range_table_func_col->colname)); + deparseAppendStringInfoChar(state, ' '); + + if (range_table_func_col->for_ordinality) + { + deparseAppendStringInfoString(state, "FOR ORDINALITY "); + } + else + { + deparseTypeName(state, range_table_func_col->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (range_table_func_col->colexpr) + { + deparseAppendStringInfoString(state, "PATH "); + deparseExpr(state, range_table_func_col->colexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); + } + + if (range_table_func_col->coldefexpr) + { + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, range_table_func_col->coldefexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); + } + + if (range_table_func_col->is_not_null) + deparseAppendStringInfoString(state, "NOT NULL "); + } + + removeTrailingSpace(state); +} + +// "table_ref" and "xmltable" in gram.y +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + deparseAppendStringInfoString(state, "xmltable("); + if (range_table_func->namespaces) + { + deparseAppendStringInfoString(state, "xmlnamespaces("); + deparseXmlNamespaceList(state, range_table_func->namespaces); + deparseAppendStringInfoString(state, "), "); + } + + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, range_table_func->rowexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); + + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, range_table_func->docexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + + deparseAppendStringInfoString(state, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(state, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoString(state, ") "); + + if (range_table_func->alias) + { + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_table_func->alias); + } + + removeTrailingSpace(state); +} + +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize) +{ + deparseAppendStringInfoString(state, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + deparseAppendStringInfoString(state, "document "); + break; + case XMLOPTION_CONTENT: + deparseAppendStringInfoString(state, "content "); + break; + default: + Assert(false); + } + deparseExpr(state, xml_serialize->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, xml_serialize->typeName); + + if (xml_serialize->indent) { + deparseAppendStringInfoString(state, " INDENT"); + } + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonFormat(DeparseState *state, JsonFormat *json_format) +{ + if (json_format == NULL || json_format->format_type == JS_FORMAT_DEFAULT) + return; + + deparseAppendStringInfoString(state, "FORMAT JSON "); + + switch (json_format->encoding) + { + case JS_ENC_UTF8: + deparseAppendStringInfoString(state, "ENCODING utf8 "); + break; + case JS_ENC_UTF16: + deparseAppendStringInfoString(state, "ENCODING utf16 "); + break; + case JS_ENC_UTF32: + deparseAppendStringInfoString(state, "ENCODING utf32 "); + break; + case JS_ENC_DEFAULT: + // no encoding specified + break; + } +} + +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *j) +{ + deparseExpr(state, j->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + deparseJsonFormat(state, castNode(JsonFormat, j->format)); + + deparseAppendStringInfoString(state, "IS "); + + switch (j->item_type) + { + case JS_TYPE_ANY: + deparseAppendStringInfoString(state, "JSON "); + break; + case JS_TYPE_ARRAY: + deparseAppendStringInfoString(state, "JSON ARRAY "); + break; + case JS_TYPE_OBJECT: + deparseAppendStringInfoString(state, "JSON OBJECT "); + break; + case JS_TYPE_SCALAR: + deparseAppendStringInfoString(state, "JSON SCALAR "); + break; + } + + if (j->unique_keys) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + removeTrailingSpace(state); +} + +// "json_value_expr" in gram.y +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr) +{ + deparseExpr(state, (Node *) json_value_expr->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_value_expr->format); +} + +// "json_value_expr_list" in gram.y +static void deparseJsonValueExprList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonValueExpr(state, lfirst(lc)); + removeTrailingSpace(state); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); +} + +// "json_name_and_value" in gram.y +static void deparseJsonKeyValue(DeparseState *state, JsonKeyValue *json_key_value) +{ + deparseExpr(state, (Node *) json_key_value->key, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ": "); + deparseJsonValueExpr(state, json_key_value->value); +} + +// "json_name_and_value_list" in gram.y +static void deparseJsonKeyValueList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonKeyValue(state, lfirst(lc)); + removeTrailingSpace(state); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); +} + +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output) +{ + if (json_output == NULL) + return; + + Assert(json_output->returning != NULL); + + deparseAppendStringInfoString(state, "RETURNING "); + deparseTypeName(state, json_output->typeName); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_output->returning->format); +} + +// "json_aggregate_func" and "func_expr" in gram.y +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg) +{ + Assert(json_object_agg->constructor != NULL); + + deparseAppendStringInfoString(state, "JSON_OBJECTAGG("); + deparseJsonKeyValue(state, json_object_agg->arg); + + if (json_object_agg->absent_on_null) + deparseAppendStringInfoString(state, "ABSENT ON NULL "); + + if (json_object_agg->unique) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + deparseJsonOutput(state, json_object_agg->constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (json_object_agg->constructor->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_object_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (json_object_agg->constructor->over) + { + struct WindowDef *over = json_object_agg->constructor->over; + deparseAppendStringInfoString(state, "OVER "); + if (over->name) + deparseAppendStringInfoString(state, over->name); + else + deparseWindowDef(state, over); + } + + removeTrailingSpace(state); +} + +// "json_aggregate_func" and "func_expr" in gram.y +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg) +{ + Assert(json_array_agg->constructor != NULL); + + deparseAppendStringInfoString(state, "JSON_ARRAYAGG("); + deparseJsonValueExpr(state, json_array_agg->arg); + deparseOptSortClause(state, json_array_agg->constructor->agg_order, DEPARSE_NODE_CONTEXT_NONE); + + if (!json_array_agg->absent_on_null) + deparseAppendStringInfoString(state, "NULL ON NULL "); + + deparseJsonOutput(state, json_array_agg->constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (json_array_agg->constructor->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_array_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (json_array_agg->constructor->over) + { + struct WindowDef *over = json_array_agg->constructor->over; + deparseAppendStringInfoString(state, "OVER "); + if (over->name) + deparseAppendStringInfoString(state, over->name); + else + deparseWindowDef(state, over); + } + + removeTrailingSpace(state); +} + +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor) +{ + deparseAppendStringInfoString(state, "JSON_OBJECT("); + deparseJsonKeyValueList(state, json_object_constructor->exprs); + + if (json_object_constructor->absent_on_null) + deparseAppendStringInfoString(state, "ABSENT ON NULL "); + + if (json_object_constructor->unique) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + deparseJsonOutput(state, json_object_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor) +{ + deparseAppendStringInfoString(state, "JSON_ARRAY("); + deparseJsonValueExprList(state, json_array_constructor->exprs); + + if (!json_array_constructor->absent_on_null) + deparseAppendStringInfoString(state, "NULL ON NULL "); + + deparseJsonOutput(state, json_array_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor) +{ + deparseAppendStringInfoString(state, "JSON_ARRAY("); + + deparseSelectStmt(state, castNode(SelectStmt, json_array_query_constructor->query), DEPARSE_NODE_CONTEXT_NONE); + deparseJsonFormat(state, json_array_query_constructor->format); + deparseJsonOutput(state, json_array_query_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr) +{ + deparseAppendStringInfoString(state, "JSON("); + + deparseJsonValueExpr(state, json_parse_expr->expr); + + if (json_parse_expr->unique_keys) + deparseAppendStringInfoString(state, " WITH UNIQUE KEYS"); + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr) +{ + deparseAppendStringInfoString(state, "JSON_SCALAR("); + deparseExpr(state, (Node*) json_scalar_expr->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr) +{ + deparseAppendStringInfoString(state, "JSON_SERIALIZE("); + + deparseJsonValueExpr(state, json_serialize_expr->expr); + + if (json_serialize_expr->output) + deparseJsonOutput(state, json_serialize_expr->output); + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes) +{ + switch (quotes) + { + case JS_QUOTES_UNSPEC: + break; + case JS_QUOTES_KEEP: + deparseAppendStringInfoString(state, " KEEP QUOTES"); + break; + case JS_QUOTES_OMIT: + deparseAppendStringInfoString(state, " OMIT QUOTES"); + break; + } +} + +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior) +{ + if (!behavior) + return; + + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON ERROR"); +} + +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior) +{ + if (behavior) + { + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON EMPTY"); + } +} + +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr) +{ + switch (json_func_expr->op) + { + case JSON_EXISTS_OP: + deparseAppendStringInfoString(state, "JSON_EXISTS("); + break; + case JSON_QUERY_OP: + deparseAppendStringInfoString(state, "JSON_QUERY("); + break; + case JSON_VALUE_OP: + deparseAppendStringInfoString(state, "JSON_VALUE("); + break; + case JSON_TABLE_OP: + deparseAppendStringInfoString(state, "JSON_TABLE("); + break; + } + + deparseJsonValueExpr(state, json_func_expr->context_item); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, json_func_expr->pathspec, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (json_func_expr->passing) + deparseAppendStringInfoString(state, " PASSING "); + + ListCell *lc = NULL; + foreach (lc, json_func_expr->passing) + { + JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); + + if (lnext(json_func_expr->passing, lc)) + deparseAppendStringInfoString(state, ", "); + } + + if (json_func_expr->output) + { + deparseAppendStringInfoChar(state, ' '); + deparseJsonOutput(state, json_func_expr->output); + } + + switch (json_func_expr->wrapper) + { + case JSW_UNSPEC: + break; + case JSW_NONE: + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); + break; + case JSW_CONDITIONAL: + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); + break; + case JSW_UNCONDITIONAL: + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); + break; + } + + deparseJsonQuotesClauseOpt(state, json_func_expr->quotes); + deparseJsonOnEmptyClauseOpt(state, json_func_expr->on_empty); + deparseJsonOnErrorClauseOpt(state, json_func_expr->on_error); + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec) +{ + deparseStringLiteral(state, castNode(A_Const, json_table_path_spec->string)->val.sval.sval); + + if (json_table_path_spec->name) + { + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_table_path_spec->name); + } +} + +// "json_behavior" in gram.y +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior) +{ + switch (json_behavior->btype) + { + case JSON_BEHAVIOR_NULL: + deparseAppendStringInfoString(state, "NULL"); + break; + case JSON_BEHAVIOR_ERROR: + deparseAppendStringInfoString(state, "ERROR"); + break; + case JSON_BEHAVIOR_EMPTY: + deparseAppendStringInfoString(state, "EMPTY"); + break; + case JSON_BEHAVIOR_TRUE: + deparseAppendStringInfoString(state, "TRUE"); + break; + case JSON_BEHAVIOR_FALSE: + deparseAppendStringInfoString(state, "FALSE"); + break; + case JSON_BEHAVIOR_EMPTY_ARRAY: + deparseAppendStringInfoString(state, "EMPTY ARRAY"); + break; + case JSON_BEHAVIOR_EMPTY_OBJECT: + deparseAppendStringInfoString(state, "EMPTY OBJECT"); + break; + case JSON_BEHAVIOR_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, (Node*) json_behavior->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + break; + case JSON_BEHAVIOR_UNKNOWN: + deparseAppendStringInfoString(state, "UNKNOWN"); + break; + } +} + +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column) +{ + if (json_table_column->coltype == JTC_NESTED) + { + deparseAppendStringInfoString(state, "NESTED PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); + deparseJsonTableColumns(state, json_table_column->columns); + return; + } + + deparseColLabel(state, json_table_column->name); + deparseAppendStringInfoChar(state, ' '); + + switch (json_table_column->coltype) + { + case JTC_FOR_ORDINALITY: + deparseAppendStringInfoString(state, " FOR ORDINALITY"); + break; + case JTC_EXISTS: + case JTC_FORMATTED: + case JTC_REGULAR: + deparseTypeName(state, json_table_column->typeName); + + if (json_table_column->coltype == JTC_EXISTS) + deparseAppendStringInfoString(state, " EXISTS "); + else + deparseAppendStringInfoChar(state, ' '); + + if (json_table_column->format) + deparseJsonFormat(state, json_table_column->format); + + if (json_table_column->pathspec) + { + deparseAppendStringInfoString(state, "PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); + } + break; + case JTC_NESTED: + Assert(false); + } + + switch (json_table_column->wrapper) + { + case JSW_UNSPEC: + break; + case JSW_NONE: + if (json_table_column->coltype == JTC_REGULAR || json_table_column->coltype == JTC_FORMATTED) + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); + break; + case JSW_CONDITIONAL: + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); + break; + case JSW_UNCONDITIONAL: + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); + break; + } + + deparseJsonQuotesClauseOpt(state, json_table_column->quotes); + deparseJsonOnEmptyClauseOpt(state, json_table_column->on_empty); + deparseJsonOnErrorClauseOpt(state, json_table_column->on_error); +} + +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns) +{ + deparseAppendStringInfoString(state, " COLUMNS ("); + + ListCell *lc = NULL; + foreach(lc, json_table_columns) + { + deparseJsonTableColumn(state, castNode(JsonTableColumn, lfirst(lc))); + + if (lnext(json_table_columns, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonTable(DeparseState *state, JsonTable *json_table) +{ + deparseAppendStringInfoString(state, "JSON_TABLE("); + + deparseJsonValueExpr(state, json_table->context_item); + deparseAppendStringInfoString(state, ", "); + deparseJsonTablePathSpec(state, json_table->pathspec); + + if (json_table->passing) + deparseAppendStringInfoString(state, " PASSING "); + + ListCell *lc = NULL; + foreach (lc, json_table->passing) + { + JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); + + if (lnext(json_table->passing, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseJsonTableColumns(state, json_table->columns); + + if (json_table->on_error) + { + deparseJsonBehavior(state, json_table->on_error); + deparseAppendStringInfoString(state, " ON ERROR"); + } + + deparseAppendStringInfoChar(state, ')'); + + if (json_table->alias) + { + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, json_table->alias); + } +} + +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func) +{ + deparseAppendStringInfoString(state, "GROUPING("); + deparseExprList(state, grouping_func->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseClusterStmt(DeparseState *state, ClusterStmt *cluster_stmt) +{ + deparseAppendStringInfoString(state, "CLUSTER "); + + deparseUtilityOptionList(state, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(state, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(cluster_stmt->indexname)); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context) +{ + if (!value) { + deparseAppendStringInfoString(state, "NULL"); + return; + } + + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(state, value); + break; + case T_Boolean: + deparseAppendStringInfoString(state, value->boolval.boolval ? "true" : "false"); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + deparseAppendStringInfoString(state, quote_identifier(value->sval.sval)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(state, value->sval.sval); + } else { + deparseAppendStringInfoString(state, value->sval.sval); + } + break; + case T_BitString: + if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') + { + deparseAppendStringInfoChar(state, 'x'); + deparseStringLiteral(state, value->sval.sval + 1); + } + else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') + { + deparseAppendStringInfoChar(state, 'b'); + deparseStringLiteral(state, value->sval.sval + 1); + } + else + { + Assert(false); + } + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(state, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(state, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(state, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(state, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(state, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(DeparseState *state, Node *node) +{ + DeparseStateNestingLevel *parent_level = NULL; + + // For statements that can be nested, push/pop is handled directly in the + // respective deparse...Stmt methods + bool skip_push_pop = IsA(node, SelectStmt) || + IsA(node, InsertStmt) || + IsA(node, UpdateStmt) || + IsA(node, DeleteStmt) || + IsA(node, MergeStmt); + + if (!skip_push_pop) + parent_level = deparseStateIncreaseNestingLevel(state); + + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(state, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(state, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(state, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(state, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(state, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(state, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(state, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(state, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(state, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(state, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(state, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(state, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(state, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(state, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(state, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(state, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(state, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(state, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(state, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(state, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableMoveAllStmt: + deparseAlterTableMoveAllStmt(state, castNode(AlterTableMoveAllStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(state, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(state, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(state, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(state, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(state, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(state, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(state, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(state, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(state, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(state, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(state, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(state, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(state, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(state, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(state, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(state, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(state, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(state, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(state, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(state, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(state, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(state, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(state, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(state, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(state, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(state, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(state, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(state, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(state, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(state, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(state, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(state, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(state, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(state, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(state, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(state, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(state, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(state, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(state, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(state, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(state, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(state, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(state, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(state, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(state, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(state, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(state, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(state, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(state, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(state, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(state, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(state, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(state, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(state, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(state, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(state, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(state, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(state, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(state, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(state, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(state, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(state, castNode(LockStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(state, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(state, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(state, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(state, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(state, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(state, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(state, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_TransactionStmt: + deparseTransactionStmt(state, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(state, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(state, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(state, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(state, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(state, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(state, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(state, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(state, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(state, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } + + if (!skip_push_pop) + deparseStateDecreaseNestingLevel(state, parent_level); +} diff --git a/postgres_deparse.h b/postgres_deparse.h new file mode 100644 index 0000000..3506aac --- /dev/null +++ b/postgres_deparse.h @@ -0,0 +1,66 @@ +// From https://github.com/pganalyze/libpg_query/tree/156705b347d347c154fdfddf9341c07a9fa73dc2 + +// Copyright (c) 2015, Lukas Fittl +// Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#ifndef POSTGRES_DEPARSE_H +#define POSTGRES_DEPARSE_H + +#include +#include + +typedef struct PostgresDeparseComment { + int match_location; // Insert comment before a node, once we find a node whose location field is equal-or-higher than this location + int newlines_before_comment; // Insert newlines before inserting the comment (set to non-zero if the source comment was separated from the prior token by at least one newline) + int newlines_after_comment; // Insert newlines after inserting the comment (set to non-zero if the source comment was separated from the next token by at least one newline) + char *str; // The actual comment string, including comment start/end tokens, and newline characters in comment (if any) +} PostgresDeparseComment; + +typedef struct PostgresDeparseOpts { + PostgresDeparseComment **comments; + size_t comment_count; + + // Pretty print options + bool pretty_print; + int indent_size; // Indentation size (Default 4 spaces) + int max_line_length; // Restricts the line length of certain lists of items (Default 80 characters) + bool trailing_newline; // Whether to add a trailing newline at the end of the output (Default off) + bool commas_start_of_line; // Place separating commas at start of line (Default off) +} PostgresDeparseOpts; + +/* Forward declarations to allow referencing the structs in this include file without needing Postgres includes */ +struct StringInfoData; +typedef struct StringInfoData *StringInfo; +struct RawStmt; + +extern void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt); +extern void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts *opts); + +#endif \ No newline at end of file diff --git a/schema/2.4.sql b/schema/2.4.sql new file mode 100644 index 0000000..8f2ca45 --- /dev/null +++ b/schema/2.4.sql @@ -0,0 +1 @@ +ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_indexes BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/sql/56_1_6_features.sql b/sql/56_1_6_features.sql index 9672768..77ac9a3 100644 --- a/sql/56_1_6_features.sql +++ b/sql/56_1_6_features.sql @@ -40,15 +40,3 @@ In <= 1.5, returned this: {"DROP SCHEMA","DROP TABLE","DROP FUNCTION","DROP TYPE","DROP VIEW","DROP SEQUENCE"} (1 row) */ - -SET client_min_messages TO warning; -DROP OWNED BY test_pgl_ddl_deploy; -DROP ROLE test_pgl_ddl_deploy; -DROP ROLE unpriv; -DROP EXTENSION pgl_ddl_deploy CASCADE; -DROP EXTENSION IF EXISTS pglogical CASCADE; -DROP SCHEMA IF EXISTS pglogical CASCADE; -DROP TABLE IF EXISTS tmp_objs; -DROP SCHEMA IF EXISTS special CASCADE; -DROP SCHEMA IF EXISTS bla CASCADE; -DROP SCHEMA IF EXISTS pgl_ddl_deploy CASCADE; diff --git a/sql/57_2_4_features.sql b/sql/57_2_4_features.sql new file mode 100644 index 0000000..ec25d6d --- /dev/null +++ b/sql/57_2_4_features.sql @@ -0,0 +1,43 @@ +SET client_min_messages = warning; + +CREATE PUBLICATION test_indexes_yes; +CREATE PUBLICATION test_indexes_no; + +INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_schema_regex, lock_safe_deployment, allow_multi_statements, include_indexes) +VALUES ('test_indexes_yes', '^yindex.*', true, true, true); + +INSERT INTO pgl_ddl_deploy.set_configs (set_name, include_schema_regex, lock_safe_deployment, allow_multi_statements, include_indexes) +VALUES ('test_indexes_no', '^nindex.*', true, true, false); + +SELECT pgl_ddl_deploy.deploy('test_indexes_yes'); +SELECT pgl_ddl_deploy.deploy('test_indexes_no'); + +CREATE SCHEMA yindex; +CREATE TABLE yindex.widgets(id serial primary key, type varchar); +CREATE SCHEMA nindex; +CREATE TABLE nindex.widgets(id serial primary key, type varchar); + +CREATE INDEX yindex_widgets_type_idx ON yindex.widgets(type); +CREATE INDEX CONCURRENTLY nindex_widgets_type_id_idx ON yindex.widgets(type, id); +CREATE INDEX nindex_widgets_type_idx ON nindex.widgets(type); + +DROP TABLE yindex.widgets CASCADE; +DROP TABLE nindex.widgets CASCADE; + +-- We expect to see index events for yindex.widgets but not for nindex.widgets +SELECT c.set_name, ddl_sql_raw, ddl_sql_sent, c.ddl_only_replication +FROM pgl_ddl_deploy.events e +INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id +ORDER BY e.id DESC LIMIT 10; + +SET client_min_messages TO warning; +DROP OWNED BY test_pgl_ddl_deploy; +DROP ROLE test_pgl_ddl_deploy; +DROP ROLE unpriv; +DROP EXTENSION pgl_ddl_deploy CASCADE; +DROP EXTENSION IF EXISTS pglogical CASCADE; +DROP SCHEMA IF EXISTS pglogical CASCADE; +DROP TABLE IF EXISTS tmp_objs; +DROP SCHEMA IF EXISTS special CASCADE; +DROP SCHEMA IF EXISTS bla CASCADE; +DROP SCHEMA IF EXISTS pgl_ddl_deploy CASCADE; diff --git a/sql/57_native_features.sql b/sql/99_native_features.sql similarity index 100% rename from sql/57_native_features.sql rename to sql/99_native_features.sql diff --git a/test_all_versions.sh b/test_all_versions.sh index 3797a0e..7ed318d 100755 --- a/test_all_versions.sh +++ b/test_all_versions.sh @@ -44,5 +44,5 @@ make_and_test "16" $from_version make_and_test "17" $from_version make_and_test "18" $from_version } +test_all_versions "2.4" test_all_versions "2.3" -test_all_versions "2.2" diff --git a/views/event_trigger_schema.sql b/views/event_trigger_schema.sql index cfebb3e..0990594 100644 --- a/views/event_trigger_schema.sql +++ b/views/event_trigger_schema.sql @@ -41,7 +41,6 @@ WITH vars AS We need to strip the DDL of: 1. Transaction begin and commit, which cannot run inside plpgsql *****/ - v_ddl_strip_regex TEXT = '(begin\W*transaction\W*|begin\W*work\W*|begin\W*|commit\W*transaction\W*|commit\W*work\W*|commit\W*);'; v_txid BIGINT; v_ddl_length INT; v_sql TEXT; @@ -193,15 +192,7 @@ WITH vars AS END LOOP; END IF; - v_ddl_sql_sent = v_ddl_sql_raw; - - --If there are BEGIN/COMMIT tags, attempt to strip and reparse - IF (SELECT ARRAY['BEGIN','COMMIT']::TEXT[] && v_sql_tags) THEN - v_ddl_sql_sent = regexp_replace(v_ddl_sql_sent, v_ddl_strip_regex, '', 'ig'); - - --Sanity reparse - PERFORM pgl_ddl_deploy.sql_command_tags(v_ddl_sql_sent); - END IF; + SELECT pgl_ddl_deploy.rewrite_transaction_safe(v_ddl_sql_raw) INTO v_ddl_sql_sent; --Get provider name, in order only to run command on a subscriber to this provider c_provider_name:=pgl_ddl_deploy.provider_node_name(c_driver); From 99ca9f34468f09f7d85b994665f412be03939976 Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 09:28:44 -0500 Subject: [PATCH 2/7] Improved drop handling with pg_toast --- README.md | 1 + ddl_deparse.c | 12 +-- expected/05_allowed.out | 24 +++--- expected/06_multi.out | 78 +++++++++++-------- expected/16_multi_set_tags.out | 14 ++-- .../20_include_only_repset_tables_4_1.out | 4 +- expected/22_is_deployed.out | 28 +++---- expected/24_sub_retries.out | 18 +---- expected/33_allowed.out | 24 +++--- expected/34_multi.out | 78 +++++++++++-------- expected/44_multi_set_tags.out | 14 ++-- .../48_include_only_repset_tables_4_1.out | 4 +- expected/50_is_deployed.out | 28 +++---- expected/52_sub_retries.out | 18 +---- ...common_exclude_alter_table_subcommands.sql | 3 - pgl_ddl_deploy--2.3--2.4.sql | 36 ++++++++- pgl_ddl_deploy--2.4.sql | 36 ++++++++- pgl_ddl_deploy-sql-maker.sh | 1 + views/event_trigger_schema.sql | 3 +- 19 files changed, 240 insertions(+), 184 deletions(-) diff --git a/README.md b/README.md index 7cb05f8..b75c885 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ https://innovation.enova.com/pursuing-postgres-ddl-replication/ ### Release 2.4 Summary of changes: * Support for replicating index DDL +* Prevent DDL that internally touches toast tables from being silently dropped ### Release 2.2 Summary of changes: diff --git a/ddl_deparse.c b/ddl_deparse.c index 794a78f..5fb3f2c 100644 --- a/ddl_deparse.c +++ b/ddl_deparse.c @@ -104,7 +104,7 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS) strtype = "ADD OIDS"; break; case AT_AddOidsRecurse: - strtype = "ADD OIDS (and recurse)"; + strtype = "ADD OIDS"; break; #endif #if PG_VERSION_NUM >= 120000 && PG_VERSION_NUM < 180000 @@ -119,19 +119,19 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS) #endif #if PG_VERSION_NUM < 160000 case AT_AddColumnRecurse: - strtype = "ADD COLUMN (and recurse)"; + strtype = "ADD COLUMN"; break; case AT_DropColumnRecurse: - strtype = "DROP COLUMN (and recurse)"; + strtype = "DROP COLUMN"; break; case AT_AddConstraintRecurse: - strtype = "ADD CONSTRAINT (and recurse)"; + strtype = "ADD CONSTRAINT"; break; case AT_ValidateConstraintRecurse: - strtype = "VALIDATE CONSTRAINT (and recurse)"; + strtype = "VALIDATE CONSTRAINT"; break; case AT_DropConstraintRecurse: - strtype = "DROP CONSTRAINT (and recurse)"; + strtype = "DROP CONSTRAINT"; break; #endif #if PG_VERSION_NUM >= 170000 diff --git a/expected/05_allowed.out b/expected/05_allowed.out index 415ee16..ebe4f19 100644 --- a/expected/05_allowed.out +++ b/expected/05_allowed.out @@ -566,18 +566,18 @@ SELECT * FROM check_rep_tables(); (0 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test6 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test5 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test4 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test3 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test2 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test1 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; - test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------+------------------------------------ + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test6 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test5 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test4 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test3 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test2 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test1 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test8 | ALTER SEQUENCE foobar.foo RESTART; | ALTER SEQUENCE foobar.foo RESTART; + test7 | ALTER SEQUENCE foobar.foo RESTART; | ALTER SEQUENCE foobar.foo RESTART; (10 rows) SELECT * FROM pgl_ddl_deploy.unhandled; diff --git a/expected/06_multi.out b/expected/06_multi.out index ffc6786..e58b38b 100644 --- a/expected/06_multi.out +++ b/expected/06_multi.out @@ -7,6 +7,8 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE +INSERT 0 3 DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); INSERT INTO foobar.foo (id) VALUES (1),(2),(3); DROP TABLE foobar.foo;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled @@ -17,20 +19,22 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE +INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------+--------------------------- + test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; @@ -52,22 +56,26 @@ SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +BEGIN +CREATE TABLE COMMIT \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +BEGIN +CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; @@ -98,22 +106,24 @@ DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------- - test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; - test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-----------------------------------------------------------------------------+------------------------------------------------------------------------------ + test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; + test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test6 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; @@ -147,18 +157,18 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+----------------------------------------------- test4 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test3 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test2 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test1 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; - test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); + test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; diff --git a/expected/16_multi_set_tags.out b/expected/16_multi_set_tags.out index 5065919..58fb130 100644 --- a/expected/16_multi_set_tags.out +++ b/expected/16_multi_set_tags.out @@ -28,13 +28,13 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - drop_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------------------------------------------------+----------+--------------------------------+-------------------------------------------------------- - {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP SCHEMA viewer; | DROP SCHEMA viewer; - {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; - {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; - {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; - | | SELECT * FROM viewer.foo; | + drop_tags | set_name | ddl_sql_raw | ddl_sql_sent +----------------------------------------------------------+----------+----------------------------------------------+-------------------------------------------------------- + {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; + {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; + {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | + {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo (id int PRIMARY KEY); (4 rows) SELECT * FROM pgl_ddl_deploy.exceptions; diff --git a/expected/20_include_only_repset_tables_4_1.out b/expected/20_include_only_repset_tables_4_1.out index 44f58f0..a68836e 100644 --- a/expected/20_include_only_repset_tables_4_1.out +++ b/expected/20_include_only_repset_tables_4_1.out @@ -45,11 +45,11 @@ LOG: Not processing DDL due to excluded subcommand(s): ENABLE TRIGGER: ALTER TA -- This contains a tag we want to ignore but we can't separate out the parts - see the warning message ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); WARNING: Filtering out more than one subcommand in one ALTER TABLE is not supported. - Allowing to proceed: Rejected: ADD CONSTRAINT (and recurse), SQL: ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); + Allowing to proceed: Rejected: ADD CONSTRAINT, SQL: ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); ALTER TABLE special.fooz ADD COLUMN bar_id INT; -- This one should be ignored as well ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); -LOG: Not processing DDL due to excluded subcommand(s): ADD CONSTRAINT (and recurse): ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); +LOG: Not processing DDL due to excluded subcommand(s): ADD CONSTRAINT: ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); SELECT c.set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id diff --git a/expected/22_is_deployed.out b/expected/22_is_deployed.out index 7a54a1b..c4df3f6 100644 --- a/expected/22_is_deployed.out +++ b/expected/22_is_deployed.out @@ -52,18 +52,18 @@ SELECT set_name, is_deployed FROM pgl_ddl_deploy.event_trigger_schema ORDER BY i CREATE TABLE foobar (id serial primary key); DROP TABLE foobar; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------+---------------------------------- - test4 | DROP SCHEMA special; | DROP SCHEMA special; - test3 | DROP SCHEMA special; | DROP SCHEMA special; - test2 | DROP SCHEMA special; | DROP SCHEMA special; - test1 | DROP SCHEMA special; | DROP SCHEMA special; - test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test2 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test1 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test4 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; - test3 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------- + test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test2 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test1 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test4 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test3 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test2 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test1 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test4 | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); + test3 | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); (10 rows) --Re-deploy and check again what shows as deployed @@ -112,7 +112,7 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); - test4 | DROP SCHEMA special; | DROP SCHEMA special; - test3 | DROP SCHEMA special; | DROP SCHEMA special; + test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; (10 rows) diff --git a/expected/24_sub_retries.out b/expected/24_sub_retries.out index 68ecb84..e94a909 100644 --- a/expected/24_sub_retries.out +++ b/expected/24_sub_retries.out @@ -156,14 +156,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SEQUENCE foobar.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SEQUENCE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SEQUENCE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -312,10 +304,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE viewer.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE viewer.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE viewer.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -412,10 +400,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE special.barz CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE special.barz CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE special.barz CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -436,7 +420,7 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE duper.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE duper.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE super.man CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE super.man CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE duper.man;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE duper.man;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " -(432 rows) +(416 rows) DO $$ DECLARE v_ct INT; diff --git a/expected/33_allowed.out b/expected/33_allowed.out index 415ee16..ebe4f19 100644 --- a/expected/33_allowed.out +++ b/expected/33_allowed.out @@ -566,18 +566,18 @@ SELECT * FROM check_rep_tables(); (0 rows) SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test6 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test5 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test4 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test3 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test2 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test1 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; - test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + set_name | ddl_sql_raw | ddl_sql_sent +----------+------------------------------------+------------------------------------ + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test6 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test5 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test4 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test3 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test2 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test1 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test8 | ALTER SEQUENCE foobar.foo RESTART; | ALTER SEQUENCE foobar.foo RESTART; + test7 | ALTER SEQUENCE foobar.foo RESTART; | ALTER SEQUENCE foobar.foo RESTART; (10 rows) SELECT * FROM pgl_ddl_deploy.unhandled; diff --git a/expected/34_multi.out b/expected/34_multi.out index ffc6786..e58b38b 100644 --- a/expected/34_multi.out +++ b/expected/34_multi.out @@ -7,6 +7,8 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE +INSERT 0 3 DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); INSERT INTO foobar.foo (id) VALUES (1),(2),(3); DROP TABLE foobar.foo;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled @@ -17,20 +19,22 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE +INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------+--------------------------- + test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; @@ -52,22 +56,26 @@ SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +BEGIN +CREATE TABLE COMMIT \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +BEGIN +CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent ----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo(id int primary key); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo(id int primary key); + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; @@ -98,22 +106,24 @@ DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled +CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------------------------------------------------------+----------------------------------------------------------------------------- - test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; - test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; - test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-----------------------------------------------------------------------------+------------------------------------------------------------------------------ + test7 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test5 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test1 | CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE; | CREATE TABLE foobar.foo (id int PRIMARY KEY); DROP TABLE foobar.foo CASCADE; + test3 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; + test1 | CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE; | CREATE TABLE foo (id int PRIMARY KEY); DROP TABLE foo CASCADE; test8 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test7 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; test6 | DROP TABLE foobar.foo CASCADE; | DROP TABLE foobar.foo CASCADE; @@ -147,18 +157,18 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------------------+---------------------------------------------- + set_name | ddl_sql_raw | ddl_sql_sent +----------+----------------------------------------------+----------------------------------------------- test4 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test3 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test2 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; test1 | DROP TABLE foo, foobar.foo CASCADE; | DROP TABLE foo, foobar.foo CASCADE; - test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); - test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo(id int primary key); + test8 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test7 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test6 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test4 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | CREATE TABLE foobar.foo(id int primary key); | CREATE TABLE foobar.foo (id int PRIMARY KEY); (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; diff --git a/expected/44_multi_set_tags.out b/expected/44_multi_set_tags.out index a83d83d..11fbe8f 100644 --- a/expected/44_multi_set_tags.out +++ b/expected/44_multi_set_tags.out @@ -28,13 +28,13 @@ FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id WHERE c.set_name = 'test1' ORDER BY e.id DESC LIMIT 4; - drop_tags | set_name | ddl_sql_raw | ddl_sql_sent -----------------------------------------------------------+----------+--------------------------------+-------------------------------------------------------- - {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP SCHEMA viewer; | DROP SCHEMA viewer; - {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; - {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; - {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; - | | SELECT * FROM viewer.foo; | + drop_tags | set_name | ddl_sql_raw | ddl_sql_sent +----------------------------------------------------------+----------+----------------------------------------------+-------------------------------------------------------- + {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | DROP TABLE viewer.foo CASCADE; | DROP TABLE viewer.foo CASCADE; + {"DROP VIEW","DROP FUNCTION"} | test1 | DROP VIEW viewer.vw_foo; | DROP VIEW viewer.vw_foo; + {"DROP VIEW","DROP FUNCTION"} | test1 | CREATE VIEW viewer.vw_foo AS +| CREATE VIEW viewer.vw_foo AS SELECT * FROM viewer.foo; + | | SELECT * FROM viewer.foo; | + {"DROP SCHEMA","DROP TABLE","DROP TYPE","DROP SEQUENCE"} | test1 | CREATE TABLE viewer.foo(id int primary key); | CREATE TABLE viewer.foo (id int PRIMARY KEY); (4 rows) SELECT * FROM pgl_ddl_deploy.exceptions; diff --git a/expected/48_include_only_repset_tables_4_1.out b/expected/48_include_only_repset_tables_4_1.out index 44f58f0..a68836e 100644 --- a/expected/48_include_only_repset_tables_4_1.out +++ b/expected/48_include_only_repset_tables_4_1.out @@ -45,11 +45,11 @@ LOG: Not processing DDL due to excluded subcommand(s): ENABLE TRIGGER: ALTER TA -- This contains a tag we want to ignore but we can't separate out the parts - see the warning message ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); WARNING: Filtering out more than one subcommand in one ALTER TABLE is not supported. - Allowing to proceed: Rejected: ADD CONSTRAINT (and recurse), SQL: ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); + Allowing to proceed: Rejected: ADD CONSTRAINT, SQL: ALTER TABLE special.barz ADD COLUMN foo_id INT REFERENCES special.fooz (id_2); ALTER TABLE special.fooz ADD COLUMN bar_id INT; -- This one should be ignored as well ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); -LOG: Not processing DDL due to excluded subcommand(s): ADD CONSTRAINT (and recurse): ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); +LOG: Not processing DDL due to excluded subcommand(s): ADD CONSTRAINT: ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); SELECT c.set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events e INNER JOIN pgl_ddl_deploy.set_configs c ON c.id = e.set_config_id diff --git a/expected/50_is_deployed.out b/expected/50_is_deployed.out index 7a54a1b..c4df3f6 100644 --- a/expected/50_is_deployed.out +++ b/expected/50_is_deployed.out @@ -52,18 +52,18 @@ SELECT set_name, is_deployed FROM pgl_ddl_deploy.event_trigger_schema ORDER BY i CREATE TABLE foobar (id serial primary key); DROP TABLE foobar; SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+----------------------------------+---------------------------------- - test4 | DROP SCHEMA special; | DROP SCHEMA special; - test3 | DROP SCHEMA special; | DROP SCHEMA special; - test2 | DROP SCHEMA special; | DROP SCHEMA special; - test1 | DROP SCHEMA special; | DROP SCHEMA special; - test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test2 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test1 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; - test4 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; - test3 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------- + test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test2 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test1 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test4 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test3 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test2 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test1 | DROP TABLE special.fooz CASCADE; | DROP TABLE special.fooz CASCADE; + test4 | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); + test3 | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); | ALTER TABLE special.fooz ADD CONSTRAINT coolness FOREIGN KEY (bar_id) REFERENCES special.barz (id_3); (10 rows) --Re-deploy and check again what shows as deployed @@ -112,7 +112,7 @@ SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY i test3 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test2 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); test1 | CREATE TABLE foobar (id serial primary key); | CREATE TABLE foobar (id serial PRIMARY KEY); - test4 | DROP SCHEMA special; | DROP SCHEMA special; - test3 | DROP SCHEMA special; | DROP SCHEMA special; + test4 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; + test3 | DROP TABLE special.barz CASCADE; | DROP TABLE special.barz CASCADE; (10 rows) diff --git a/expected/52_sub_retries.out b/expected/52_sub_retries.out index 46554ee..934e93e 100644 --- a/expected/52_sub_retries.out +++ b/expected/52_sub_retries.out @@ -156,14 +156,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SEQUENCE foobar.foo;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SEQUENCE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SEQUENCE foobar.foo;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SEQUENCE foobar.foo;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA foobar CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA foobar CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA foobar CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -312,10 +304,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE viewer.foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE viewer.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE viewer.foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE viewer.foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA viewer;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA viewer;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA viewer;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -412,10 +400,6 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE special.barz CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE special.barz CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE special.barz CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE special.barz CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP SCHEMA special;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test4} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test4'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP SCHEMA special;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP SCHEMA special;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 4,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar (id serial PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foobar_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar (id serial PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar (id serial PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " @@ -436,7 +420,7 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := 'duper',\n p_relname := 'man',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$ALTER TABLE duper.man ADD COLUMN foo text;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n ALTER TABLE duper.man ADD COLUMN foo text;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE super.man CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE super.man CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 19,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test_ddl_only} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test_ddl_only'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE duper.man;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO '';\n\n DROP TABLE duper.man;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 20,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " -(432 rows) +(416 rows) DO $$ DECLARE v_ct INT; diff --git a/functions/common_exclude_alter_table_subcommands.sql b/functions/common_exclude_alter_table_subcommands.sql index 2f7f4fd..9507737 100644 --- a/functions/common_exclude_alter_table_subcommands.sql +++ b/functions/common_exclude_alter_table_subcommands.sql @@ -3,15 +3,12 @@ RETURNS TEXT[] AS $BODY$ SELECT ARRAY[ 'ADD CONSTRAINT', - 'ADD CONSTRAINT (and recurse)', '(re) ADD CONSTRAINT', 'ALTER CONSTRAINT', 'VALIDATE CONSTRAINT', - 'VALIDATE CONSTRAINT (and recurse)', 'ADD (processed) CONSTRAINT', 'ADD CONSTRAINT (using index)', 'DROP CONSTRAINT', - 'DROP CONSTRAINT (and recurse)', 'SET LOGGED', 'SET UNLOGGED', 'SET TABLESPACE', diff --git a/pgl_ddl_deploy--2.3--2.4.sql b/pgl_ddl_deploy--2.3--2.4.sql index fbbdd95..65fd634 100644 --- a/pgl_ddl_deploy--2.3--2.4.sql +++ b/pgl_ddl_deploy--2.3--2.4.sql @@ -6,6 +6,39 @@ ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_indexes BOOLEAN NOT NULL DEFAULT FALSE; +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.common_exclude_alter_table_subcommands() +RETURNS TEXT[] AS +$BODY$ +SELECT ARRAY[ + 'ADD CONSTRAINT', + '(re) ADD CONSTRAINT', + 'ALTER CONSTRAINT', + 'VALIDATE CONSTRAINT', + 'ADD (processed) CONSTRAINT', + 'ADD CONSTRAINT (using index)', + 'DROP CONSTRAINT', + 'SET LOGGED', + 'SET UNLOGGED', + 'SET TABLESPACE', + 'SET RELOPTIONS', + 'RESET RELOPTIONS', + 'REPLACE RELOPTIONS', + 'ENABLE TRIGGER', + 'ENABLE TRIGGER (always)', + 'ENABLE TRIGGER (replica)', + 'DISABLE TRIGGER', + 'ENABLE TRIGGER (all)', + 'DISABLE TRIGGER (all)', + 'ENABLE TRIGGER (user)', + 'DISABLE TRIGGER (user)', + 'ENABLE RULE', + 'ENABLE RULE (always)', + 'ENABLE RULE (replica)', + 'DISABLE RULE', + 'SET OPTIONS']::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rewrite_transaction_safe(p_sql text) RETURNS text LANGUAGE c @@ -313,7 +346,8 @@ WITH vars AS $BUILD$::TEXT AS shared_mixed_obj_logic, $BUILD$ -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) - (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + -- Also filter out toast tables since if there are any non-toast operations the toast ones are almost certainly internally generated + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%' AND schema_name <> 'pg_toast') $BUILD$::TEXT AS dropped_objects_query, $BUILD$ diff --git a/pgl_ddl_deploy--2.4.sql b/pgl_ddl_deploy--2.4.sql index 70fb847..01649fc 100644 --- a/pgl_ddl_deploy--2.4.sql +++ b/pgl_ddl_deploy--2.4.sql @@ -5172,6 +5172,39 @@ FROM build b; ALTER TABLE pgl_ddl_deploy.set_configs ADD COLUMN include_indexes BOOLEAN NOT NULL DEFAULT FALSE; +CREATE OR REPLACE FUNCTION pgl_ddl_deploy.common_exclude_alter_table_subcommands() +RETURNS TEXT[] AS +$BODY$ +SELECT ARRAY[ + 'ADD CONSTRAINT', + '(re) ADD CONSTRAINT', + 'ALTER CONSTRAINT', + 'VALIDATE CONSTRAINT', + 'ADD (processed) CONSTRAINT', + 'ADD CONSTRAINT (using index)', + 'DROP CONSTRAINT', + 'SET LOGGED', + 'SET UNLOGGED', + 'SET TABLESPACE', + 'SET RELOPTIONS', + 'RESET RELOPTIONS', + 'REPLACE RELOPTIONS', + 'ENABLE TRIGGER', + 'ENABLE TRIGGER (always)', + 'ENABLE TRIGGER (replica)', + 'DISABLE TRIGGER', + 'ENABLE TRIGGER (all)', + 'DISABLE TRIGGER (all)', + 'ENABLE TRIGGER (user)', + 'DISABLE TRIGGER (user)', + 'ENABLE RULE', + 'ENABLE RULE (always)', + 'ENABLE RULE (replica)', + 'DISABLE RULE', + 'SET OPTIONS']::TEXT[]; +$BODY$ +LANGUAGE SQL IMMUTABLE; + CREATE OR REPLACE FUNCTION pgl_ddl_deploy.rewrite_transaction_safe(p_sql text) RETURNS text LANGUAGE c @@ -5479,7 +5512,8 @@ WITH vars AS $BUILD$::TEXT AS shared_mixed_obj_logic, $BUILD$ -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) - (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + -- Also filter out toast tables since if there are any non-toast operations the toast ones are almost certainly internally generated + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%' AND schema_name <> 'pg_toast') $BUILD$::TEXT AS dropped_objects_query, $BUILD$ diff --git a/pgl_ddl_deploy-sql-maker.sh b/pgl_ddl_deploy-sql-maker.sh index 1ec4778..848ccac 100755 --- a/pgl_ddl_deploy-sql-maker.sh +++ b/pgl_ddl_deploy-sql-maker.sh @@ -37,6 +37,7 @@ create_update_file_with_header # Add view and function changes add_file schema/2.4.sql $update_file +add_file functions/common_exclude_alter_table_subcommands.sql $update_file add_file functions/rewrite_transaction_safe.sql $update_file add_file functions/set_tag_defaults.sql $update_file add_file views/event_trigger_schema.sql $update_file diff --git a/views/event_trigger_schema.sql b/views/event_trigger_schema.sql index 0990594..76a2223 100644 --- a/views/event_trigger_schema.sql +++ b/views/event_trigger_schema.sql @@ -276,7 +276,8 @@ WITH vars AS $BUILD$::TEXT AS shared_mixed_obj_logic, $BUILD$ -- Filter out purely PG-internal triggers (alas, "pg_event_trigger_dropped_objects" does not expose "tgisinternal", so we must filter by name) - (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%') + -- Also filter out toast tables since if there are any non-toast operations the toast ones are almost certainly internally generated + (SELECT * FROM pg_event_trigger_dropped_objects() WHERE address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_a_%' AND address_names[array_upper(address_names, 1)] NOT LIKE 'RI_ConstraintTrigger_c_%' AND schema_name <> 'pg_toast') $BUILD$::TEXT AS dropped_objects_query, $BUILD$ From 169de2a2edaa377ce0c318a316e161a59a023dbf Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 09:30:07 -0500 Subject: [PATCH 3/7] Add older versions of deparse --- Makefile | 10 +- pgl_ddl_deploy.c => src/pgl_ddl_deploy.c | 0 src/postgres_deparse.11.c | 35 + src/postgres_deparse.12.c | 35 + src/postgres_deparse.13.c | 9938 +++++++++++++ src/postgres_deparse.14.c | 10295 +++++++++++++ src/postgres_deparse.15.c | 10716 ++++++++++++++ src/postgres_deparse.16.c | 11103 ++++++++++++++ src/postgres_deparse.17.c | 12143 ++++++++++++++++ .../postgres_deparse.18.c | 6 +- postgres_deparse.h => src/postgres_deparse.h | 4 + 11 files changed, 54283 insertions(+), 2 deletions(-) rename pgl_ddl_deploy.c => src/pgl_ddl_deploy.c (100%) create mode 100644 src/postgres_deparse.11.c create mode 100644 src/postgres_deparse.12.c create mode 100644 src/postgres_deparse.13.c create mode 100644 src/postgres_deparse.14.c create mode 100644 src/postgres_deparse.15.c create mode 100644 src/postgres_deparse.16.c create mode 100644 src/postgres_deparse.17.c rename postgres_deparse.c => src/postgres_deparse.18.c (99%) rename postgres_deparse.h => src/postgres_deparse.h (95%) diff --git a/Makefile b/Makefile index 20b80c2..9e1ab02 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,15 @@ DATA = pgl_ddl_deploy--1.0.sql pgl_ddl_deploy--1.0--1.1.sql \ pgl_ddl_deploy--2.4.sql MODULES = ddl_deparse MODULE_big = pgl_ddl_deploy -OBJS = postgres_deparse.o pgl_ddl_deploy.o +OBJS = src/postgres_deparse.11.o \ + src/postgres_deparse.12.o \ + src/postgres_deparse.13.o \ + src/postgres_deparse.14.o \ + src/postgres_deparse.15.o \ + src/postgres_deparse.16.o \ + src/postgres_deparse.17.o \ + src/postgres_deparse.18.o \ + src/pgl_ddl_deploy.o REGRESS := 01_create_ext 02_setup 03_add_configs 04_deploy 04_deploy_update \ 05_allowed 06_multi 07_edges 08_ignored \ diff --git a/pgl_ddl_deploy.c b/src/pgl_ddl_deploy.c similarity index 100% rename from pgl_ddl_deploy.c rename to src/pgl_ddl_deploy.c diff --git a/src/postgres_deparse.11.c b/src/postgres_deparse.11.c new file mode 100644 index 0000000..6a97adc --- /dev/null +++ b/src/postgres_deparse.11.c @@ -0,0 +1,35 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 11) + +// Copyright (c) 2015, Lukas Fittl +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" + +#endif \ No newline at end of file diff --git a/src/postgres_deparse.12.c b/src/postgres_deparse.12.c new file mode 100644 index 0000000..4f86901 --- /dev/null +++ b/src/postgres_deparse.12.c @@ -0,0 +1,35 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 12) + +// Copyright (c) 2015, Lukas Fittl +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" + +#endif \ No newline at end of file diff --git a/src/postgres_deparse.13.c b/src/postgres_deparse.13.c new file mode 100644 index 0000000..d144649 --- /dev/null +++ b/src/postgres_deparse.13.c @@ -0,0 +1,9938 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 13) + +// Adapted from https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/13-2.2.0/src/pg_query_deparse.c + +// Copyright (c) 2015, Lukas Fittl +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "limits.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context); + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(roles, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, Value *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->val.ival); + break; + case T_Float: + appendStringInfoString(str, value->val.str); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (Value *) lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (Value *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + foreach(lc, object_with_args->objargs) + { + if (IsA(lfirst(lc), TypeName)) + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + else + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + if (lnext(object_with_args->objargs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, object_with_args->objargs) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(object_with_args->objargs, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (Value *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + case T_FuncCall: + case T_SQLValueFunction: + case T_TypeCast: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_XmlSerialize: + deparseFuncExprWindowless(str, index_elem->expr); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(str, index_elem->opclassopts); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(stmt->valuesLists, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(stmt->windowClause, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + appendStringInfoString(str, "LIMIT "); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && IsA(&castNode(A_Const, stmt->limitCount)->val, Null)) + appendStringInfoString(str, "ALL"); + else + deparseCExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + deparseValue(str, &a_const->val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(func_call->args, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OF: /* IS [NOT] OF - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IS OF "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "IS NOT OF "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + deparseTypeList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(castNode(List, a_expr->rexpr), lc)) + appendStringInfoString(str, " AND "); + } + return; + case AEXPR_PAREN: /* nameless dummy node for parentheses */ + // Not present in parse trees when operator_precedence_warning is turned off + Assert(false); + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(range_func->functions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr)) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + } + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + appendStringInfoString(str, "interval"); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + deparseExpr(str, (Node *) boolean_test->arg); + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, column_def->colname); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + switch (insert_stmt->override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, constraint->conname); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON DELETE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + // Default + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (Value *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseStringLiteral(str, strVal(linitial(drop_stmt->objects))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (alter_object_depends_stmt->remove) + appendStringInfoString(str, "NO "); + + appendStringInfoString(str, "DEPENDS ON EXTENSION "); + deparseColId(str, strVal(alter_object_depends_stmt->extname)); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseNodeContext context = DEPARSE_NODE_CONTEXT_NONE; + + appendStringInfoString(str, "ALTER "); + + switch (alter_table_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + context = DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + appendStringInfoString(str, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + if (list_length(vacuum_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, vacuum_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (Value *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + if (lnext(vacuum_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + if (list_length(explain_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + + foreach(lc, explain_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL && IsA(def_elem->arg, String)) + { + appendStringInfoChar(str, ' '); + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (def_elem->arg != NULL && (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float))) + { + appendStringInfoChar(str, ' '); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + + if (lnext(explain_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "FREEZE"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "HEADER"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, index_stmt->idxname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + if (reindex_stmt->options & REINDEXOPT_VERBOSE) + appendStringInfoString(str, "(VERBOSE) "); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + deparseStringLiteral(str, create_table_space_stmt->location); + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->tables) > 0) + { + appendStringInfoString(str, "FOR TABLE "); + deparseRelationExprList(str, create_publication_stmt->tables); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->tables) > 0) + { + switch (alter_publication_stmt->tableAction) + { + case DEFELEM_SET: + appendStringInfoString(str, "SET TABLE "); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD TABLE "); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP TABLE "); + break; + case DEFELEM_UNSPEC: + Assert(false); + break; + } + + deparseRelationExprList(str, alter_publication_stmt->tables); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (Value *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + deparseExprList(str, create_stats_stmt->exprs); + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +{ + appendStringInfoString(str, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseAnyName(str, alter_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "SESSION ALL"); + else + appendStringInfoString(str, variable_show_stmt->name); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (intVal(defelem->arg) == 1) + { + appendStringInfoString(str, " ENABLE "); + } + else if (intVal(defelem->arg) == 0) + { + appendStringInfoString(str, " DISABLE "); + } + else + { + Assert(false); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (Value *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(defs, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_type_stmt->typeName); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_type_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + if (strcmp(strVal(&castNode(A_Const, castNode(TypeCast, lsecond(xml_expr->args))->arg)->val), "t") == 0) + appendStringInfoString(str, " PRESERVE WHITESPACE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (nodeTag(&castNode(A_Const, lsecond(xml_expr->args))->val) == T_Null) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + if (cluster_stmt->options & CLUOPT_VERBOSE) + appendStringInfoString(str, "VERBOSE "); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context) +{ + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->val.str)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->val.str); + } else { + appendStringInfoString(str, value->val.str); + } + break; + case T_BitString: + if (strlen(value->val.str) >= 1 && value->val.str[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->val.str + 1); + } + else if (strlen(value->val.str) >= 1 && value->val.str[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->val.str + 1); + } + else + { + Assert(false); + } + break; + case T_Null: + appendStringInfoString(str, "NULL"); + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif diff --git a/src/postgres_deparse.14.c b/src/postgres_deparse.14.c new file mode 100644 index 0000000..dc1bbe2 --- /dev/null +++ b/src/postgres_deparse.14.c @@ -0,0 +1,10295 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 14) + +// Adapted from https://github.com/pganalyze/libpg_query/blob/14-3.0.0/src/pg_query_deparse.c + +// Copyright (c) 2015, Lukas Fittl +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "limits.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context); + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(roles, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, Value *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->val.ival); + break; + case T_Float: + appendStringInfoString(str, value->val.str); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (Value *) lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (Value *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (Value *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + case T_FuncCall: + case T_SQLValueFunction: + case T_TypeCast: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_XmlSerialize: + deparseFuncExprWindowless(str, index_elem->expr); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(str, index_elem->opclassopts); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(StringInfo str, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (Value *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(stmt->valuesLists, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + if (stmt->groupDistinct) + appendStringInfoString(str, "DISTINCT "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(stmt->windowClause, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + appendStringInfoString(str, "LIMIT "); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && IsA(&castNode(A_Const, stmt->limitCount)->val, Null)) + appendStringInfoString(str, "ALL"); + else + deparseCExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + deparseValue(str, &a_const->val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + appendStringInfoString(str, "SUBSTRING("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + if (list_length(func_call->args) == 3) + { + appendStringInfoString(str, " FOR "); + deparseExpr(str, lthird(func_call->args)); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + appendStringInfoString(str, "POSITION("); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " IN "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "overlay("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " placing "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " from "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "collation for ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + appendStringInfoString(str, "extract ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, ") "); + + appendStringInfoString(str, "overlaps "); + appendStringInfoChar(str, '('); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoString(str, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + appendStringInfoString(str, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + appendStringInfoString(str, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + appendStringInfoString(str, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) == 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " AT TIME ZONE "); + deparseExpr(str, linitial(func_call->args)); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "normalize ("); + + deparseExpr(str, linitial(func_call->args)); + if (list_length(func_call->args) == 2) + { + appendStringInfoString(str, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoString(str, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + appendStringInfoString(str, "xmlexists ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PASSING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(func_call->args, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(castNode(List, a_expr->rexpr), lc)) + appendStringInfoString(str, " AND "); + } + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + + if (join_expr->join_using_alias) + { + appendStringInfoString(str, "AS "); + appendStringInfoString(str, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) +{ + appendStringInfoString(str, " SEARCH "); + if (search_clause->search_breadth_first) + appendStringInfoString(str, "BREADTH "); + else + appendStringInfoString(str, "DEPTH "); + + appendStringInfoString(str, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(str, search_clause->search_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); +} + +static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) +{ + appendStringInfoString(str, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(str, cycle_clause->cycle_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + appendStringInfoString(str, " TO "); + deparseExpr(str, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + appendStringInfoString(str, " DEFAULT "); + deparseExpr(str, cycle_clause->cycle_mark_default); + } + + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); + + if (cte->search_clause) + deparseCTESearchClause(str, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(str, cte->cycle_clause); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(range_func->functions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr)) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + appendStringInfoString(str, " point "); + deparseAConst(str, a_const); + return; + } + } + + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + appendStringInfoString(str, "interval"); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + deparseExpr(str, (Node *) boolean_test->arg); + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, column_def->colname); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + switch (insert_stmt->override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, constraint->conname); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON DELETE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) +{ + appendStringInfoString(str, "RETURN "); + deparseExpr(str, return_stmt->returnval); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); + else + { + appendStringInfoString(str, "BEGIN ATOMIC "); + deparseExprList(str, castNode(List, create_function_stmt->sql_body)); + appendStringInfoString(str, "END "); + } + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + appendStringInfoString(str, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + appendStringInfoString(str, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } + if (partition_cmd->concurrent) + appendStringInfoString(str, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (Value *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (alter_object_depends_stmt->remove) + appendStringInfoString(str, "NO "); + + appendStringInfoString(str, "DEPENDS ON EXTENSION "); + deparseColId(str, strVal(alter_object_depends_stmt->extname)); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoString(str, "FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + appendStringInfoString(str, "DEFAULT"); + else + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseNodeContext context = DEPARSE_NODE_CONTEXT_NONE; + + appendStringInfoString(str, "ALTER "); + + switch (alter_table_stmt->objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + context = DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + appendStringInfoString(str, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + deparseUtilityOptionList(str, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + deparseUtilityOptionList(str, explain_stmt->options); + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "FREEZE"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "HEADER"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "ADMIN OPTION FOR "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + if (grant_role_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, index_stmt->idxname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + deparseUtilityOptionList(str, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + deparseStringLiteral(str, create_table_space_stmt->location); + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->tables) > 0) + { + appendStringInfoString(str, "FOR TABLE "); + deparseRelationExprList(str, create_publication_stmt->tables); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->tables) > 0) + { + switch (alter_publication_stmt->tableAction) + { + case DEFELEM_SET: + appendStringInfoString(str, "SET TABLE "); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD TABLE "); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP TABLE "); + break; + case DEFELEM_UNSPEC: + Assert(false); + break; + } + + deparseRelationExprList(str, alter_publication_stmt->tables); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (Value *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + appendStringInfoString(str, stats_elem->name); + else if (stats_elem->expr) + { + appendStringInfoChar(str, '('); + deparseExpr(str, stats_elem->expr); + appendStringInfoChar(str, ')'); + } +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(str, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +{ + appendStringInfoString(str, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseAnyName(str, alter_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "SESSION ALL"); + else + appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + appendStringInfoString(str, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + appendStringInfoString(str, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (intVal(defelem->arg) == 1) + { + appendStringInfoString(str, " ENABLE "); + } + else if (intVal(defelem->arg) == 0) + { + appendStringInfoString(str, " DISABLE "); + } + else + { + Assert(false); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (Value *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(defs, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_type_stmt->typeName); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_type_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + if (strcmp(strVal(&castNode(A_Const, castNode(TypeCast, lsecond(xml_expr->args))->arg)->val), "t") == 0) + appendStringInfoString(str, " PRESERVE WHITESPACE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (nodeTag(&castNode(A_Const, lsecond(xml_expr->args))->val) == T_Null) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + + deparseUtilityOptionList(str, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context) +{ + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->val.str)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->val.str); + } else { + appendStringInfoString(str, value->val.str); + } + break; + case T_BitString: + if (strlen(value->val.str) >= 1 && value->val.str[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->val.str + 1); + } + else if (strlen(value->val.str) >= 1 && value->val.str[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->val.str + 1); + } + else + { + Assert(false); + } + break; + case T_Null: + appendStringInfoString(str, "NULL"); + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif diff --git a/src/postgres_deparse.15.c b/src/postgres_deparse.15.c new file mode 100644 index 0000000..6606305 --- /dev/null +++ b/src/postgres_deparse.15.c @@ -0,0 +1,10716 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 15) + +// From https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/16-5.2.0/src/postgres_deparse.c + +// Copyright (c) 2015, Lukas Fittl +// Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + DEPARSE_NODE_CONTEXT_SET_STATEMENT, + DEPARSE_NODE_CONTEXT_FUNC_EXPR, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context); + + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(roles, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, union ValUnion *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->ival.ival); + break; + case T_Float: + appendStringInfoString(str, value->sval.sval); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (union ValUnion *) lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +static void deparseOptBoolean(StringInfo str, Node *node) +{ + if (node == NULL) + { + return; + } + + switch (nodeTag(node)) + { + case T_String: + appendStringInfo(str, " %s", strVal(node)); + break; + case T_Integer: + appendStringInfo(str, " %d", intVal(node)); + break; + case T_Boolean: + appendStringInfo(str, " %s", boolVal(node) ? "TRUE" : "FALSE"); + break; + default: + Assert(false); + break; + } +} + +bool optBooleanValue(Node *node) +{ + if (node == NULL) + { + return true; + } + + switch (nodeTag(node)) + { + case T_String: { + // Longest valid string is "off\0" + char lower[4]; + strncpy(lower, strVal(node), 4); + lower[3] = 0; + + if (strcmp(lower, "on") == 0) { + return true; + } else if (strcmp(lower, "off") == 0) { + return false; + } + + // No sane way to handle this. + return false; + } + case T_Integer: + return intVal(node) != 0; + case T_Boolean: + return boolVal(node); + default: + Assert(false); + return false; + } +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (union ValUnion *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else if (IsA(lfirst(lc), TypeCast)) + { + deparseTypeCast(str, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + // Simple function calls can be written without wrapping parens + case T_FuncCall: // func_application + case T_SQLValueFunction: // func_expr_common_subexpr + case T_CoalesceExpr: // func_expr_common_subexpr + case T_MinMaxExpr: // func_expr_common_subexpr + case T_XmlExpr: // func_expr_common_subexpr + case T_XmlSerialize: // func_expr_common_subexpr + deparseFuncExprWindowless(str, index_elem->expr); + appendStringInfoString(str, " "); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(str, index_elem->opclassopts); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(StringInfo str, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(stmt->valuesLists, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + if (stmt->groupDistinct) + appendStringInfoString(str, "DISTINCT "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(stmt->windowClause, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + appendStringInfoString(str, "LIMIT "); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) + appendStringInfoString(str, "ALL"); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseCExpr(str, stmt->limitCount); + else + deparseExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + union ValUnion *val = a_const->isnull ? NULL : &a_const->val; + deparseValue(str, val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + appendStringInfoString(str, "SUBSTRING("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + if (list_length(func_call->args) == 3) + { + appendStringInfoString(str, " FOR "); + deparseExpr(str, lthird(func_call->args)); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + appendStringInfoString(str, "POSITION("); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " IN "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "overlay("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " placing "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " from "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "collation for ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + appendStringInfoString(str, "extract ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, ") "); + + appendStringInfoString(str, "overlaps "); + appendStringInfoChar(str, '('); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoString(str, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + appendStringInfoString(str, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + appendStringInfoString(str, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + appendStringInfoString(str, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) == 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " AT TIME ZONE "); + deparseExpr(str, linitial(func_call->args)); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "normalize ("); + + deparseExpr(str, linitial(func_call->args)); + if (list_length(func_call->args) == 2) + { + appendStringInfoString(str, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoString(str, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + appendStringInfoString(str, "xmlexists ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PASSING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(func_call->args, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, BooleanTest) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, BooleanTest) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(castNode(List, a_expr->rexpr), lc)) + appendStringInfoString(str, " AND "); + } + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + + if (join_expr->join_using_alias) + { + appendStringInfoString(str, "AS "); + appendStringInfoString(str, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) +{ + appendStringInfoString(str, " SEARCH "); + if (search_clause->search_breadth_first) + appendStringInfoString(str, "BREADTH "); + else + appendStringInfoString(str, "DEPTH "); + + appendStringInfoString(str, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(str, search_clause->search_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); +} + +static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) +{ + appendStringInfoString(str, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(str, cycle_clause->cycle_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + appendStringInfoString(str, " TO "); + deparseExpr(str, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + appendStringInfoString(str, " DEFAULT "); + deparseExpr(str, cycle_clause->cycle_mark_default); + } + + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); + + if (cte->search_clause) + deparseCTESearchClause(str, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(str, cte->cycle_clause); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(range_func->functions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr) || context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) + { + appendStringInfoString(str, "interval "); + deparseAConst(str, a_const); + deparseIntervalTypmods(str, type_cast->typeName); + return; + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + appendStringInfoString(str, " point "); + deparseAConst(str, a_const); + return; + } + } + + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + appendStringInfoString(str, "interval"); + deparseIntervalTypmods(str, type_name); + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +// Handle typemods for Interval types separately +// so that they can be applied appropriately for different contexts. +// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` +// the `INTERVAL` keyword is specified first. +// In all other contexts, intervals use the `'x'::interval` style. +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) +{ + const char *name = strVal(lsecond(type_name->names)); + Assert(strcmp(name, "interval") == 0); + Assert(list_length(type_name->typmods) >= 1); + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + bool need_parens = IsA(boolean_test->arg, BoolExpr); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, (Node *) boolean_test->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, quote_identifier(column_def->colname)); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertOverride(StringInfo str, OverridingKind override) +{ + switch (override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, insert_stmt->override); + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) +{ + if (merge_stmt->withClause != NULL) + { + deparseWithClause(str, merge_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "MERGE INTO "); + deparseRangeVar(str, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + deparseTableRef(str, merge_stmt->sourceRelation); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + deparseExpr(str, merge_stmt->joinCondition); + appendStringInfoChar(str, ' '); + + ListCell *lc, *lc2; + foreach (lc, merge_stmt->mergeWhenClauses) + { + MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); + + appendStringInfoString(str, "WHEN "); + + if (!clause->matched) + { + appendStringInfoString(str, "NOT "); + } + + appendStringInfoString(str, "MATCHED "); + + if (clause->condition) + { + appendStringInfoString(str, "AND "); + deparseExpr(str, clause->condition); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "THEN "); + + switch (clause->commandType) { + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + + if (clause->targetList) { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, clause->targetList); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, clause->override); + + if (clause->values) { + appendStringInfoString(str, "VALUES ("); + deparseExprList(str, clause->values); + appendStringInfoString(str, ")"); + } else { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE SET "); + deparseSetClauseList(str, clause->targetList); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE"); + break; + case CMD_NOTHING: + appendStringInfoString(str, "DO NOTHING"); + break; + default: + elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); + break; + } + + if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, quote_identifier(constraint->conname)); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET "); + + switch (constraint->fk_del_action) { + case FKCONSTR_ACTION_SETDEFAULT: appendStringInfoString(str, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: appendStringInfoString(str, "NULL "); break; + } + + if (constraint->fk_del_set_cols) { + appendStringInfoString(str, "("); + ListCell *lc; + foreach (lc, constraint->fk_del_set_cols) { + appendStringInfoString(str, strVal(lfirst(lc))); + if (lfirst(lc) != llast(constraint->fk_del_set_cols)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); + } + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + case CONSTR_UNIQUE: + case CONSTR_EXCLUSION: + deparseOptWith(str, constraint->options); + break; + default: + break; + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) +{ + appendStringInfoString(str, "RETURN "); + deparseExpr(str, return_stmt->returnval); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + { + deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); + } + else + { + appendStringInfoString(str, "BEGIN ATOMIC "); + if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) + { + List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); + foreach(lc, body_stmt_list) + { + if (IsA(lfirst(lc), ReturnStmt)) + { + deparseReturnStmt(str, lfirst_node(ReturnStmt, lc)); + appendStringInfoString(str, "; "); + } + else + { + deparseStmt(str, lfirst(lc)); + appendStringInfoString(str, "; "); + } + } + } + + appendStringInfoString(str, "END "); + } + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + appendStringInfoString(str, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + appendStringInfoString(str, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } + if (partition_cmd->concurrent) + appendStringInfoString(str, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (alter_object_depends_stmt->remove) + appendStringInfoString(str, "NO "); + + appendStringInfo(str, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_SetAccessMethod: + appendStringInfo(str, "SET ACCESS METHOD "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER ALL "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoString(str, "FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + appendStringInfoString(str, "DEFAULT"); + else + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType type) +{ + switch (type) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + return DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + return DEPARSE_NODE_CONTEXT_NONE; +} + +static void deparseAlterTableMoveAllStmt(StringInfo str, AlterTableMoveAllStmt *move_all_stmt) +{ + appendStringInfoString(str, "ALTER "); + deparseAlterTableObjType(str, move_all_stmt->objtype); + + appendStringInfoString(str, "ALL IN TABLESPACE "); + appendStringInfoString(str, move_all_stmt->orig_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->roles) + { + appendStringInfoString(str, "OWNED BY "); + deparseRoleList(str, move_all_stmt->roles); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "SET TABLESPACE "); + appendStringInfoString(str, move_all_stmt->new_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->nowait) + { + appendStringInfoString(str, "NOWAIT"); + } +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(str, alter_table_stmt->objtype); + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +// Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not +// supported for other SET statements +static bool isSetTimeZoneInterval(VariableSetStmt* stmt) +{ + if (!(strcmp(stmt->name, "timezone") == 0 && + list_length(stmt->args) == 1 && + IsA(linitial(stmt->args), TypeCast))) + return false; + + TypeName* typeName = castNode(TypeCast, linitial(stmt->args))->typeName; + + return (list_length(typeName->names) == 2 && + strcmp(strVal(linitial(typeName->names)), "pg_catalog") == 0 && + strcmp(strVal(llast(typeName->names)), "interval") == 0); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (isSetTimeZoneInterval(variable_set_stmt)) + { + appendStringInfoString(str, "TIME ZONE "); + deparseVarList(str, variable_set_stmt->args); + } + else + { + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + } + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + appendStringInfoString(str, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + deparseUtilityOptionList(str, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + deparseUtilityOptionList(str, explain_stmt->options); + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + // In some cases, equivalent expressions may have slightly different parse trees for `COPY` + // statements. For example the following two statements result in different (but equivalent) parse + // trees: + // + // - COPY foo FROM STDIN CSV FREEZE + // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) + // + // In order to make sure we deparse to the "correct" version, we always try to deparse to the older + // compact syntax first. + // + // The old syntax can be seen here in the Postgres 8.4 Reference: + // https://www.postgresql.org/docs/8.4/sql-copy.html + + bool old_fmt = true; + + // Loop over the options to see if any require the new `WITH (...)` syntax. + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + {} + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + {} + else + { + old_fmt = false; + break; + } + } + + // Branch to differing output modes, depending on if we can use the old syntax. + if (old_fmt) { + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "FREEZE "); + } + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "HEADER "); + } + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + { + appendStringInfoString(str, "CSV "); + } + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + { + appendStringInfoString(str, "FORCE QUOTE "); + deparseColumnList(str, castNode(List, def_elem->arg)); + } + else + { + // This isn't reachable, the conditions here are exactly the same as the first loop above. + Assert(false); + } + } + } else { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0) + { + appendStringInfoString(str, "FREEZE"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0) + { + appendStringInfoString(str, "HEADER"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "ADMIN OPTION FOR "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + if (grant_role_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, quote_identifier(index_stmt->idxname)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (index_stmt->nulls_not_distinct) + { + appendStringInfoString(str, "NULLS NOT DISTINCT "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + deparseUtilityOptionList(str, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + case CMD_MERGE: + appendStringInfoString(str, "MERGE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + + if (create_table_space_stmt->location != NULL) + deparseStringLiteral(str, create_table_space_stmt->location); + else + appendStringInfoString(str, "''"); + + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { + const ListCell *lc; + foreach(lc, pubobjects) { + PublicationObjSpec *obj = lfirst(lc); + + switch (obj->pubobjtype) { + case PUBLICATIONOBJ_TABLE: + appendStringInfoString(str, "TABLE "); + deparseRangeVar(str, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + + if (obj->pubtable->columns) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, obj->pubtable->columns); + appendStringInfoChar(str, ')'); + } + + if (obj->pubtable->whereClause) + { + appendStringInfoString(str, " WHERE ("); + deparseExpr(str, obj->pubtable->whereClause); + appendStringInfoString(str, ")"); + } + + break; + case PUBLICATIONOBJ_TABLES_IN_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA "); + appendStringInfoString(str, quote_identifier(obj->name)); + break; + case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA CURRENT_SCHEMA"); + break; + case PUBLICATIONOBJ_CONTINUATION: + // This should be unreachable, the parser merges these before we can even get here. + Assert(false); + break; + } + + if (lnext(pubobjects, lc)) { + appendStringInfoString(str, ", "); + } + } +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->pubobjects) > 0) + { + appendStringInfoString(str, "FOR "); + deparsePublicationObjectList(str, create_publication_stmt->pubobjects); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->pubobjects) > 0) + { + switch (alter_publication_stmt->action) + { + case AP_SetObjects: + appendStringInfoString(str, "SET "); + break; + case AP_AddObjects: + appendStringInfoString(str, "ADD "); + break; + case AP_DropObjects: + appendStringInfoString(str, "DROP "); + break; + } + + deparsePublicationObjectList(str, alter_publication_stmt->pubobjects); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + appendStringInfoString(str, stats_elem->name); + else if (stats_elem->expr) + { + appendStringInfoChar(str, '('); + deparseExpr(str, stats_elem->expr); + appendStringInfoChar(str, ')'); + } +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(str, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +{ + appendStringInfoString(str, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseAnyName(str, alter_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "ALL"); + else + appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SKIP: + appendStringInfoString(str, "SKIP "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + appendStringInfoString(str, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + appendStringInfoString(str, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (optBooleanValue(defelem->arg)) + { + appendStringInfoString(str, " ENABLE "); + } + else + { + appendStringInfoString(str, " DISABLE "); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (union ValUnion *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(defs, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_type_stmt->typeName); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_type_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (castNode(A_Const, lsecond(xml_expr->args))->isnull) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + + deparseUtilityOptionList(str, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context) +{ + if (!value) { + appendStringInfoString(str, "NULL"); + return; + } + + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_Boolean: + appendStringInfoString(str, value->boolval.boolval ? "true" : "false"); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->sval.sval)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->sval.sval); + } else { + appendStringInfoString(str, value->sval.sval); + } + break; + case T_BitString: + if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else + { + Assert(false); + } + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableMoveAllStmt: + deparseAlterTableMoveAllStmt(str, castNode(AlterTableMoveAllStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif diff --git a/src/postgres_deparse.16.c b/src/postgres_deparse.16.c new file mode 100644 index 0000000..7ae9f1a --- /dev/null +++ b/src/postgres_deparse.16.c @@ -0,0 +1,11103 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 16) + +// From https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/16-5.2.0/src/postgres_deparse.c + +// Copyright (c) 2015, Lukas Fittl +// Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + DEPARSE_NODE_CONTEXT_SET_STATEMENT, + DEPARSE_NODE_CONTEXT_FUNC_EXPR, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseJsonIsPredicate(StringInfo str, JsonIsPredicate *json_is_predicate); +static void deparseJsonObjectAgg(StringInfo str, JsonObjectAgg *json_object_agg); +static void deparseJsonArrayAgg(StringInfo str, JsonArrayAgg *json_array_agg); +static void deparseJsonObjectConstructor(StringInfo str, JsonObjectConstructor *json_object_constructor); +static void deparseJsonArrayConstructor(StringInfo str, JsonArrayConstructor *json_array_constructor); +static void deparseJsonArrayQueryConstructor(StringInfo str, JsonArrayQueryConstructor *json_array_query_constructor); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context); + + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + } +} + +// "func_expr" in gram.y +static void deparseFuncExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_JsonObjectAgg: + deparseJsonObjectAgg(str, castNode(JsonObjectAgg, node)); + break; + case T_JsonArrayAgg: + deparseJsonArrayAgg(str, castNode(JsonArrayAgg, node)); + break; + case T_JsonObjectConstructor: + deparseJsonObjectConstructor(str, castNode(JsonObjectConstructor, node)); + break; + case T_JsonArrayConstructor: + deparseJsonArrayConstructor(str, castNode(JsonArrayConstructor, node)); + break; + case T_JsonArrayQueryConstructor: + deparseJsonArrayQueryConstructor(str, castNode(JsonArrayQueryConstructor, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in func_expr: %d", + (int) nodeTag(node)); + break; + } +} + +static void deparseCExpr(StringInfo str, Node *node); + +// "a_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_ColumnRef: + case T_A_Const: + case T_ParamRef: + case T_A_Indirection: + case T_CaseExpr: + case T_SubLink: + case T_A_ArrayExpr: + case T_RowExpr: + case T_GroupingFunc: + deparseCExpr(str, node); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_JsonIsPredicate: + deparseJsonIsPredicate(str, castNode(JsonIsPredicate, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(str, node); + break; + default: + // Note that this is also the fallthrough for deparseBExpr and deparseCExpr + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr/c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "b_expr" in gram.y +static void deparseBExpr(StringInfo str, Node *node) +{ + if (IsA(node, XmlExpr)) { + deparseXmlExpr(str, castNode(XmlExpr, node)); + return; + } + + if (IsA(node, A_Expr)) { + A_Expr *a_expr = castNode(A_Expr, node); + // Other kinds are handled by "c_expr", with parens added around them + if (a_expr->kind == AEXPR_OP || a_expr->kind == AEXPR_DISTINCT || a_expr->kind == AEXPR_NOT_DISTINCT) { + deparseAExpr(str, a_expr, DEPARSE_NODE_CONTEXT_NONE); + return; + } + } + + if (IsA(node, BoolExpr)) { + BoolExpr *bool_expr = castNode(BoolExpr, node); + if (bool_expr->boolop == NOT_EXPR) { + deparseBoolExpr(str, bool_expr); + return; + } + } + + deparseCExpr(str, node); +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(str, node); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, node); + appendStringInfoChar(str, ')'); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(roles, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, union ValUnion *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->ival.ival); + break; + case T_Float: + appendStringInfoString(str, value->sval.sval); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (union ValUnion *) lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +static void deparseOptBoolean(StringInfo str, Node *node) +{ + if (node == NULL) + { + return; + } + + switch (nodeTag(node)) + { + case T_String: + appendStringInfo(str, " %s", strVal(node)); + break; + case T_Integer: + appendStringInfo(str, " %d", intVal(node)); + break; + case T_Boolean: + appendStringInfo(str, " %s", boolVal(node) ? "TRUE" : "FALSE"); + break; + default: + Assert(false); + break; + } +} + +bool optBooleanValue(Node *node) +{ + if (node == NULL) + { + return true; + } + + switch (nodeTag(node)) + { + case T_String: { + // Longest valid string is "off\0" + char lower[4]; + strncpy(lower, strVal(node), 4); + lower[3] = 0; + + if (strcmp(lower, "on") == 0) { + return true; + } else if (strcmp(lower, "off") == 0) { + return false; + } + + // No sane way to handle this. + return false; + } + case T_Integer: + return intVal(node) != 0; + case T_Boolean: + return boolVal(node); + default: + Assert(false); + return false; + } +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (union ValUnion *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else if (IsA(lfirst(lc), TypeCast)) + { + deparseTypeCast(str, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "where_or_current_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereOrCurrentClause(StringInfo str, Node *node) +{ + if (node == NULL) + return; + + appendStringInfoString(str, "WHERE "); + + if (IsA(node, CurrentOfExpr)) { + CurrentOfExpr *current_of_expr = castNode(CurrentOfExpr, node); + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); + } else { + deparseExpr(str, node); + } + + appendStringInfoChar(str, ' '); +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" and "json_array_aggregate_order_by_clause_opt" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + // Simple function calls can be written without wrapping parens + case T_FuncCall: // func_application + case T_SQLValueFunction: // func_expr_common_subexpr + case T_CoalesceExpr: // func_expr_common_subexpr + case T_MinMaxExpr: // func_expr_common_subexpr + case T_XmlExpr: // func_expr_common_subexpr + case T_XmlSerialize: // func_expr_common_subexpr + deparseFuncExprWindowless(str, index_elem->expr); + appendStringInfoString(str, " "); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(str, index_elem->opclassopts); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(StringInfo str, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(stmt->valuesLists, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + if (stmt->groupDistinct) + appendStringInfoString(str, "DISTINCT "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(stmt->windowClause, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + appendStringInfoString(str, "LIMIT "); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) + appendStringInfoString(str, "ALL"); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseCExpr(str, stmt->limitCount); + else + deparseExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + union ValUnion *val = a_const->isnull ? NULL : &a_const->val; + deparseValue(str, val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + appendStringInfoString(str, "SUBSTRING("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + if (list_length(func_call->args) == 3) + { + appendStringInfoString(str, " FOR "); + deparseExpr(str, lthird(func_call->args)); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + appendStringInfoString(str, "POSITION("); + deparseBExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " IN "); + deparseBExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "overlay("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " placing "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " from "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "collation for ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + appendStringInfoString(str, "extract ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, ") "); + + appendStringInfoString(str, "overlaps "); + appendStringInfoChar(str, '('); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoString(str, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + appendStringInfoString(str, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + appendStringInfoString(str, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + appendStringInfoString(str, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) == 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + Expr* e = lsecond(func_call->args); + + if (IsA(e, A_Expr)) { + appendStringInfoChar(str, '('); + } + + deparseExpr(str, (Node*) e); + + if (IsA(e, A_Expr)) { + appendStringInfoChar(str, ')'); + } + + appendStringInfoString(str, " AT TIME ZONE "); + deparseExpr(str, linitial(func_call->args)); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "normalize ("); + + deparseExpr(str, linitial(func_call->args)); + if (list_length(func_call->args) == 2) + { + appendStringInfoString(str, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoString(str, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + appendStringInfoString(str, "xmlexists ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PASSING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "system_user") == 0) + { + appendStringInfoString(str, "SYSTEM_USER"); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(func_call->args, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, BooleanTest) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, BooleanTest) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(castNode(List, a_expr->rexpr), lc)) + appendStringInfoString(str, " AND "); + } + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_RIGHT_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + + if (join_expr->join_using_alias) + { + appendStringInfoString(str, "AS "); + appendStringInfoString(str, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) +{ + appendStringInfoString(str, " SEARCH "); + if (search_clause->search_breadth_first) + appendStringInfoString(str, "BREADTH "); + else + appendStringInfoString(str, "DEPTH "); + + appendStringInfoString(str, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(str, search_clause->search_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); +} + +static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) +{ + appendStringInfoString(str, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(str, cycle_clause->cycle_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + appendStringInfoString(str, " TO "); + deparseExpr(str, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + appendStringInfoString(str, " DEFAULT "); + deparseExpr(str, cycle_clause->cycle_mark_default); + } + + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); + + if (cte->search_clause) + deparseCTESearchClause(str, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(str, cte->cycle_clause); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(range_func->functions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr) || context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) + { + appendStringInfoString(str, "interval "); + deparseAConst(str, a_const); + deparseIntervalTypmods(str, type_cast->typeName); + return; + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + appendStringInfoString(str, " point "); + deparseAConst(str, a_const); + return; + } + } + + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + appendStringInfoString(str, "interval"); + deparseIntervalTypmods(str, type_name); + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +// Handle typemods for Interval types separately +// so that they can be applied appropriately for different contexts. +// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` +// the `INTERVAL` keyword is specified first. +// In all other contexts, intervals use the `'x'::interval` style. +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) +{ + const char *name = strVal(lsecond(type_name->names)); + Assert(strcmp(name, "interval") == 0); + Assert(list_length(type_name->typmods) >= 1); + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + bool need_parens = IsA(boolean_test->arg, BoolExpr); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, (Node *) boolean_test->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, quote_identifier(column_def->colname)); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->storage_name) + { + appendStringInfoString(str, "STORAGE "); + appendStringInfoString(str, column_def->storage_name); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->compression != NULL) + { + appendStringInfoString(str, "COMPRESSION "); + appendStringInfoString(str, column_def->compression); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertOverride(StringInfo str, OverridingKind override) +{ + switch (override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, insert_stmt->override); + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereOrCurrentClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) +{ + if (merge_stmt->withClause != NULL) + { + deparseWithClause(str, merge_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "MERGE INTO "); + deparseRangeVar(str, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + deparseTableRef(str, merge_stmt->sourceRelation); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + deparseExpr(str, merge_stmt->joinCondition); + appendStringInfoChar(str, ' '); + + ListCell *lc, *lc2; + foreach (lc, merge_stmt->mergeWhenClauses) + { + MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); + + appendStringInfoString(str, "WHEN "); + + if (!clause->matched) + { + appendStringInfoString(str, "NOT "); + } + + appendStringInfoString(str, "MATCHED "); + + if (clause->condition) + { + appendStringInfoString(str, "AND "); + deparseExpr(str, clause->condition); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "THEN "); + + switch (clause->commandType) { + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + + if (clause->targetList) { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, clause->targetList); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, clause->override); + + if (clause->values) { + appendStringInfoString(str, "VALUES ("); + deparseExprList(str, clause->values); + appendStringInfoString(str, ")"); + } else { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE SET "); + deparseSetClauseList(str, clause->targetList); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE"); + break; + case CMD_NOTHING: + appendStringInfoString(str, "DO NOTHING"); + break; + default: + elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); + break; + } + + if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereOrCurrentClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) + appendStringInfoString(str, "INCLUDING COMPRESSION "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, quote_identifier(constraint->conname)); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseBExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + if (constraint->nulls_not_distinct) + appendStringInfoString(str, "NULLS NOT DISTINCT "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET "); + + switch (constraint->fk_del_action) { + case FKCONSTR_ACTION_SETDEFAULT: appendStringInfoString(str, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: appendStringInfoString(str, "NULL "); break; + } + + if (constraint->fk_del_set_cols) { + appendStringInfoString(str, "("); + ListCell *lc; + foreach (lc, constraint->fk_del_set_cols) { + appendStringInfoString(str, strVal(lfirst(lc))); + if (lfirst(lc) != llast(constraint->fk_del_set_cols)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); + } + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + case CONSTR_UNIQUE: + case CONSTR_EXCLUSION: + deparseOptWith(str, constraint->options); + break; + default: + break; + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) +{ + appendStringInfoString(str, "RETURN "); + deparseExpr(str, return_stmt->returnval); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + { + deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); + } + else + { + appendStringInfoString(str, "BEGIN ATOMIC "); + if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) + { + List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); + foreach(lc, body_stmt_list) + { + if (IsA(lfirst(lc), ReturnStmt)) + { + deparseReturnStmt(str, lfirst_node(ReturnStmt, lc)); + appendStringInfoString(str, "; "); + } + else + { + deparseStmt(str, lfirst(lc)); + appendStringInfoString(str, "; "); + } + } + } + + appendStringInfoString(str, "END "); + } + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + appendStringInfoString(str, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + appendStringInfoString(str, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + + switch (partition_spec->strategy) + { + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "LIST"); + break; + case PARTITION_STRATEGY_HASH: + appendStringInfoString(str, "HASH"); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "RANGE"); + break; + } + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } + if (partition_cmd->concurrent) + appendStringInfoString(str, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (alter_object_depends_stmt->remove) + appendStringInfoString(str, "NO "); + + appendStringInfo(str, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_SetAccessMethod: + appendStringInfo(str, "SET ACCESS METHOD "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER ALL "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoString(str, "FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + appendStringInfoString(str, "DEFAULT"); + else + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType type) +{ + switch (type) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + return DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + return DEPARSE_NODE_CONTEXT_NONE; +} + +static void deparseAlterTableMoveAllStmt(StringInfo str, AlterTableMoveAllStmt *move_all_stmt) +{ + appendStringInfoString(str, "ALTER "); + deparseAlterTableObjType(str, move_all_stmt->objtype); + + appendStringInfoString(str, "ALL IN TABLESPACE "); + appendStringInfoString(str, move_all_stmt->orig_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->roles) + { + appendStringInfoString(str, "OWNED BY "); + deparseRoleList(str, move_all_stmt->roles); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "SET TABLESPACE "); + appendStringInfoString(str, move_all_stmt->new_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->nowait) + { + appendStringInfoString(str, "NOWAIT"); + } +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(str, alter_table_stmt->objtype); + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +// Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not +// supported for other SET statements +static bool isSetTimeZoneInterval(VariableSetStmt* stmt) +{ + if (!(strcmp(stmt->name, "timezone") == 0 && + list_length(stmt->args) == 1 && + IsA(linitial(stmt->args), TypeCast))) + return false; + + TypeName* typeName = castNode(TypeCast, linitial(stmt->args))->typeName; + + return (list_length(typeName->names) == 2 && + strcmp(strVal(linitial(typeName->names)), "pg_catalog") == 0 && + strcmp(strVal(llast(typeName->names)), "interval") == 0); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (isSetTimeZoneInterval(variable_set_stmt)) + { + appendStringInfoString(str, "TIME ZONE "); + deparseVarList(str, variable_set_stmt->args); + } + else + { + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + } + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + appendStringInfoString(str, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + deparseUtilityOptionList(str, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + deparseUtilityOptionList(str, explain_stmt->options); + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + // In some cases, equivalent expressions may have slightly different parse trees for `COPY` + // statements. For example the following two statements result in different (but equivalent) parse + // trees: + // + // - COPY foo FROM STDIN CSV FREEZE + // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) + // + // In order to make sure we deparse to the "correct" version, we always try to deparse to the older + // compact syntax first. + // + // The old syntax can be seen here in the Postgres 8.4 Reference: + // https://www.postgresql.org/docs/8.4/sql-copy.html + + bool old_fmt = true; + + // Loop over the options to see if any require the new `WITH (...)` syntax. + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + {} + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + {} + else + { + old_fmt = false; + break; + } + } + + // Branch to differing output modes, depending on if we can use the old syntax. + if (old_fmt) { + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "FREEZE "); + } + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "HEADER "); + } + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + { + appendStringInfoString(str, "CSV "); + } + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + { + appendStringInfoString(str, "FORCE QUOTE "); + deparseColumnList(str, castNode(List, def_elem->arg)); + } + else + { + // This isn't reachable, the conditions here are exactly the same as the first loop above. + Assert(false); + } + } + } else { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else if (strcmp(format, "text") == 0) + appendStringInfoString(str, "TEXT"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0) + { + appendStringInfoString(str, "FREEZE"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0) + { + appendStringInfoString(str, "HEADER"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_role_stmt->is_grant && list_length(grant_role_stmt->opt)) { + DefElem *defelem = castNode(DefElem, linitial(grant_role_stmt->opt)); + Assert(!castNode(Boolean, defelem->arg)->boolval); + + if (strcmp("admin", defelem->defname) == 0) { + appendStringInfoString(str, "ADMIN "); + } else if (strcmp("inherit", defelem->defname) == 0) { + appendStringInfoString(str, "INHERIT "); + } else if (strcmp("set", defelem->defname) == 0) { + appendStringInfoString(str, "SET "); + } + + appendStringInfoString(str, "OPTION FOR "); + } + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->is_grant) { + if (list_length(grant_role_stmt->opt) > 0) { + appendStringInfoString(str, "WITH "); + } + + foreach(lc, grant_role_stmt->opt) { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp("admin", defelem->defname) == 0) { + appendStringInfoString(str, "ADMIN "); + appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("inherit", defelem->defname) == 0) { + appendStringInfoString(str, "INHERIT "); + appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("set", defelem->defname) == 0) { + appendStringInfoString(str, "SET "); + appendStringInfoString(str, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } + + if (lnext(grant_role_stmt->opt, lc)) { + appendStringInfoChar(str, ','); + } + + appendStringInfoChar(str, ' '); + } + } + + if (grant_role_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + if (grant_role_stmt->behavior == DROP_CASCADE) { + appendStringInfoString(str, "CASCADE "); + } + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, quote_identifier(index_stmt->idxname)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (index_stmt->nulls_not_distinct) + { + appendStringInfoString(str, "NULLS NOT DISTINCT "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, quote_identifier(fetch_stmt->portalname)); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + deparseUtilityOptionList(str, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + case CMD_MERGE: + appendStringInfoString(str, "MERGE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + + if (create_table_space_stmt->location != NULL) + deparseStringLiteral(str, create_table_space_stmt->location); + else + appendStringInfoString(str, "''"); + + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { + const ListCell *lc; + foreach(lc, pubobjects) { + PublicationObjSpec *obj = lfirst(lc); + + switch (obj->pubobjtype) { + case PUBLICATIONOBJ_TABLE: + appendStringInfoString(str, "TABLE "); + deparseRangeVar(str, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + + if (obj->pubtable->columns) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, obj->pubtable->columns); + appendStringInfoChar(str, ')'); + } + + if (obj->pubtable->whereClause) + { + appendStringInfoString(str, " WHERE ("); + deparseExpr(str, obj->pubtable->whereClause); + appendStringInfoString(str, ")"); + } + + break; + case PUBLICATIONOBJ_TABLES_IN_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA "); + appendStringInfoString(str, quote_identifier(obj->name)); + break; + case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA CURRENT_SCHEMA"); + break; + case PUBLICATIONOBJ_CONTINUATION: + // This should be unreachable, the parser merges these before we can even get here. + Assert(false); + break; + } + + if (lnext(pubobjects, lc)) { + appendStringInfoString(str, ", "); + } + } +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->pubobjects) > 0) + { + appendStringInfoString(str, "FOR "); + deparsePublicationObjectList(str, create_publication_stmt->pubobjects); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->pubobjects) > 0) + { + switch (alter_publication_stmt->action) + { + case AP_SetObjects: + appendStringInfoString(str, "SET "); + break; + case AP_AddObjects: + appendStringInfoString(str, "ADD "); + break; + case AP_DropObjects: + appendStringInfoString(str, "DROP "); + break; + } + + deparsePublicationObjectList(str, alter_publication_stmt->pubobjects); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + appendStringInfoString(str, stats_elem->name); + else if (stats_elem->expr) + { + appendStringInfoChar(str, '('); + deparseExpr(str, stats_elem->expr); + appendStringInfoChar(str, ')'); + } +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(str, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +{ + appendStringInfoString(str, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseAnyName(str, alter_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "ALL"); + else + appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SKIP: + appendStringInfoString(str, "SKIP "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + appendStringInfoString(str, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + appendStringInfoString(str, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (optBooleanValue(defelem->arg)) + { + appendStringInfoString(str, " ENABLE "); + } + else + { + appendStringInfoString(str, " DISABLE "); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (union ValUnion *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(defs, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_type_stmt->typeName); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_type_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (castNode(A_Const, lsecond(xml_expr->args))->isnull) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + + if (xml_serialize->indent) { + appendStringInfoString(str, " INDENT"); + } + + appendStringInfoString(str, ")"); +} + +static void deparseJsonFormat(StringInfo str, JsonFormat *json_format) +{ + if (json_format == NULL || json_format->format_type == JS_FORMAT_DEFAULT) + return; + + appendStringInfoString(str, "FORMAT JSON "); + + switch (json_format->encoding) + { + case JS_ENC_UTF8: + appendStringInfoString(str, "ENCODING utf8 "); + break; + case JS_ENC_UTF16: + appendStringInfoString(str, "ENCODING utf16 "); + break; + case JS_ENC_UTF32: + appendStringInfoString(str, "ENCODING utf32 "); + break; + case JS_ENC_DEFAULT: + // no encoding specified + break; + } +} + +static void deparseJsonIsPredicate(StringInfo str, JsonIsPredicate *j) +{ + deparseExpr(str, j->expr); + appendStringInfoChar(str, ' '); + + deparseJsonFormat(str, castNode(JsonFormat, j->format)); + + appendStringInfoString(str, "IS "); + + switch (j->item_type) + { + case JS_TYPE_ANY: + appendStringInfoString(str, "JSON "); + break; + case JS_TYPE_ARRAY: + appendStringInfoString(str, "JSON ARRAY "); + break; + case JS_TYPE_OBJECT: + appendStringInfoString(str, "JSON OBJECT "); + break; + case JS_TYPE_SCALAR: + appendStringInfoString(str, "JSON SCALAR "); + break; + } + + if (j->unique_keys) + appendStringInfoString(str, "WITH UNIQUE "); + + removeTrailingSpace(str); +} + +// "json_value_expr" in gram.y +static void deparseJsonValueExpr(StringInfo str, JsonValueExpr *json_value_expr) +{ + deparseExpr(str, (Node *) json_value_expr->raw_expr); + appendStringInfoChar(str, ' '); + deparseJsonFormat(str, json_value_expr->format); +} + +// "json_value_expr_list" in gram.y +static void deparseJsonValueExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonValueExpr(str, lfirst(lc)); + removeTrailingSpace(str); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); +} + +// "json_name_and_value" in gram.y +static void deparseJsonKeyValue(StringInfo str, JsonKeyValue *json_key_value) +{ + deparseExpr(str, (Node *) json_key_value->key); + appendStringInfoString(str, ": "); + deparseJsonValueExpr(str, json_key_value->value); +} + +// "json_name_and_value_list" in gram.y +static void deparseJsonKeyValueList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonKeyValue(str, lfirst(lc)); + removeTrailingSpace(str); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); +} + +static void deparseJsonOutput(StringInfo str, JsonOutput *json_output) +{ + if (json_output == NULL) + return; + + Assert(json_output->returning != NULL); + + appendStringInfoString(str, "RETURNING "); + deparseTypeName(str, json_output->typeName); + appendStringInfoChar(str, ' '); + deparseJsonFormat(str, json_output->returning->format); +} + +static void deparseJsonObjectAgg(StringInfo str, JsonObjectAgg *json_object_agg) +{ + Assert(json_object_agg->constructor != NULL); + + appendStringInfoString(str, "JSON_OBJECTAGG("); + deparseJsonKeyValue(str, json_object_agg->arg); + + if (json_object_agg->absent_on_null) + appendStringInfoString(str, "ABSENT ON NULL "); + + if (json_object_agg->unique) + appendStringInfoString(str, "WITH UNIQUE "); + + deparseJsonOutput(str, json_object_agg->constructor->output); + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (json_object_agg->constructor->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, json_object_agg->constructor->agg_filter); + appendStringInfoString(str, ") "); + } + + if (json_object_agg->constructor->over) + { + struct WindowDef *over = json_object_agg->constructor->over; + appendStringInfoString(str, "OVER "); + if (over->name) + appendStringInfoString(str, over->name); + else + deparseWindowDef(str, over); + } + + removeTrailingSpace(str); +} + +static void deparseJsonArrayAgg(StringInfo str, JsonArrayAgg *json_array_agg) +{ + Assert(json_array_agg->constructor != NULL); + + appendStringInfoString(str, "JSON_ARRAYAGG("); + deparseJsonValueExpr(str, json_array_agg->arg); + deparseOptSortClause(str, json_array_agg->constructor->agg_order); + + if (!json_array_agg->absent_on_null) + appendStringInfoString(str, "NULL ON NULL "); + + deparseJsonOutput(str, json_array_agg->constructor->output); + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (json_array_agg->constructor->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, json_array_agg->constructor->agg_filter); + appendStringInfoString(str, ") "); + } + + if (json_array_agg->constructor->over) + { + struct WindowDef *over = json_array_agg->constructor->over; + appendStringInfoString(str, "OVER "); + if (over->name) + appendStringInfoString(str, over->name); + else + deparseWindowDef(str, over); + } + + removeTrailingSpace(str); +} + +static void deparseJsonObjectConstructor(StringInfo str, JsonObjectConstructor *json_object_constructor) +{ + appendStringInfoString(str, "JSON_OBJECT("); + deparseJsonKeyValueList(str, json_object_constructor->exprs); + + if (json_object_constructor->absent_on_null) + appendStringInfoString(str, "ABSENT ON NULL "); + + if (json_object_constructor->unique) + appendStringInfoString(str, "WITH UNIQUE "); + + deparseJsonOutput(str, json_object_constructor->output); + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseJsonArrayConstructor(StringInfo str, JsonArrayConstructor *json_array_constructor) +{ + appendStringInfoString(str, "JSON_ARRAY("); + deparseJsonValueExprList(str, json_array_constructor->exprs); + + if (!json_array_constructor->absent_on_null) + appendStringInfoString(str, "NULL ON NULL "); + + deparseJsonOutput(str, json_array_constructor->output); + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseJsonArrayQueryConstructor(StringInfo str, JsonArrayQueryConstructor *json_array_query_constructor) +{ + appendStringInfoString(str, "JSON_ARRAY("); + + deparseSelectStmt(str, castNode(SelectStmt, json_array_query_constructor->query)); + deparseJsonFormat(str, json_array_query_constructor->format); + deparseJsonOutput(str, json_array_query_constructor->output); + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + + deparseUtilityOptionList(str, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context) +{ + if (!value) { + appendStringInfoString(str, "NULL"); + return; + } + + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_Boolean: + appendStringInfoString(str, value->boolval.boolval ? "true" : "false"); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->sval.sval)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->sval.sval); + } else { + appendStringInfoString(str, value->sval.sval); + } + break; + case T_BitString: + if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else + { + Assert(false); + } + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableMoveAllStmt: + deparseAlterTableMoveAllStmt(str, castNode(AlterTableMoveAllStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif diff --git a/src/postgres_deparse.17.c b/src/postgres_deparse.17.c new file mode 100644 index 0000000..634bbf1 --- /dev/null +++ b/src/postgres_deparse.17.c @@ -0,0 +1,12143 @@ +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 17) + +// From https://github.com/pganalyze/libpg_query/blob/17-6.2.2/src/postgres_deparse.c + +// Copyright (c) 2015, Lukas Fittl +// Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) +// All rights reserved. + +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: + +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. + +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. + +// * Neither the name of pg_query nor the names of its contributors may be used +// to endorse or promote products derived from this software without specific +// prior written permission. + +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include "postgres_deparse.h" + +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +/* + * # Deparser overview + * + * The deparser works by walking the input parse tree and emitting into the + * currently active "part" as pointed to (indirectly) by the state struct. + * + * A lot of the structure of the deparser described below is meant to support + * the optional "pretty print" mode that can be enabled and configured through + * the deparser options, and inserts whitespace (newlines/spaces) as needed to + * make the output easier to read. + * + * ## Nesting levels + * + * Starting at the state struct we have a currently active "nesting level", + * which indicates the base indentation, as well as contains one or more part + * groups, each of which has one or more parts. + * + * Nesting levels are typically opened, or "increased", when processing a new + * statement contained within other statements, or for certain statement-like + * constructs (e.g. CASE clauses) that require custom indendation. + * + * Nesting levels are closed, or "decreased", when exiting such statements or + * statement-like constructs. During this operation all parts and subparts get + * flattened (turned into a simple list of parts), and are added to the parent + * nesting level. + * + * At the end of the tree walk the parts of the top most nesting level get + * emitted into the output string, formatted based on the deparse options. + * + * ## Part groups + * + * Part groups are usually started for each "major" keyword, which is chosen + * for how the output is intended to be laid out. For example, the "FROM" + * keyword in a SELECT statement is considered "major" and starts a new part + * group, vs the "JOIN" keyword is not, and as such both regular tables and + * JOIN clauses will be within one part group. + * + * ## Parts, indentation and merging + * + * The parts contained in part groups may be indented one additional level + * beyond the base indentation of the currently active nesting level, to help + * differentiate them from the major keywords. This can be turned off with + * DEPARSE_PART_NO_INDENT, for example as needed to format WITH clauses + * effectively. + * + * Parts may be merged with other parts within the same group, if the indent + * mode is set to DEPARSE_PART_INDENT_AND_MERGE. This is utilized to put + * certain items, for example the target list items in SELECT on one or more + * lines, breaking at separators as needed to respect the maximum line limit. + * + * ## Node context + * + * Node context is used when the same function in the deparser needs to behave + * differently depending on the parent node. For example, a SELECT statement + * needs wrapping parenthesis in certain situations where the parent statement + * uses a set operation (e.g. UNION). + * + * ## Comments + * + * Comments do not exist as nodes in a Postgres parse tree, and as such need to + * be passed in separately through the deparser options. They are placed in the + * output on a best effort basis, by matching against node locations. Comments + * will only be output at most once, but may not be output at all in certain + * cases, for example when the comment's specified match location is never + * reached by any of the nodes visited. + */ + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_SELECT, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + DEPARSE_NODE_CONTEXT_SET_STATEMENT, + DEPARSE_NODE_CONTEXT_FUNC_EXPR, + DEPARSE_NODE_CONTEXT_SELECT_SETOP, + DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +typedef enum DeparsePartIndentMode { + /* Don't indent parts at all, used in special cases (e.g. WITH clauses) */ + DEPARSE_PART_NO_INDENT, + + /* Indent parts but don't merge them (keep each on their own line) */ + DEPARSE_PART_INDENT, + + /* Indent parts and merge them together up to the max line length */ + DEPARSE_PART_INDENT_AND_MERGE +} DeparsePartIndentMode; + +// Each part is typically one line to be emitted in pretty print mode +typedef struct DeparseStatePart +{ + StringInfo str; + + /* If this gets emitted as its own line, number of spaces to be added as indentation */ + int indent; + + /* Allow merging this part with adjacent parts that are marked as mergeable */ + bool mergeable; +} DeparseStatePart; + +// A part group are typically all parts associated with a major keyword +typedef struct DeparseStatePartGroup +{ + const char *keyword; + List *parts; + DeparsePartIndentMode indent_mode; +} DeparseStatePartGroup; + +// Nesting levels may be statements, or complex parts of statements that should be indented (e.g. CASE) +typedef struct DeparseStateNestingLevel +{ + /* List of DeparseStatePartGroup items */ + List *part_groups; + + /* Add this much indentation to every part */ + int base_indent; +} DeparseStateNestingLevel; + +typedef struct DeparseState +{ + DeparseStateNestingLevel *current; + + /* List of DeparseStatePart items */ + List *result_parts; + + /* Deparse options originally passed in */ + PostgresDeparseOpts opts; + + /* Set of indexes of comments already placed in the output query */ + Bitmapset *emitted_comments; +} DeparseState; + +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context); +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause); +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(DeparseState *state, ResTarget *res_target, DeparseNodeContext context); +static void deparseAlias(DeparseState *state, Alias *alias); +static void deparseWindowDef(DeparseState *state, WindowDef* window_def); +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref); +static void deparseSubLink(DeparseState *state, SubLink* sub_link); +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr); +static void deparseAStar(DeparseState *state, A_Star* a_star); +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause); +static void deparseSortBy(DeparseState *state, SortBy* sort_by); +static void deparseParamRef(DeparseState *state, ParamRef* param_ref); +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function); +static void deparseWithClause(DeparseState *state, WithClause *with_clause); +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr); +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte); +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect); +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func); +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr * array_expr); +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr); +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(DeparseState *state, TypeName *type_name); +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name); +static void deparseNullTest(DeparseState *state, NullTest *null_test); +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr); +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when); +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection); +static void deparseAIndices(DeparseState *state, A_Indices *a_indices); +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test); +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def); +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt); +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem); +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt); +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt); +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause); +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default); +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter); +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec); +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt); +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func); +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set); +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context); +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context); +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize); +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *json_is_predicate); +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg); +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg); +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor); +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor); +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor); +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr); +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output); +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr); +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr); +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr); +static void deparseJsonTable(DeparseState *state, JsonTable *json_table); +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column); +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns); +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec); +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior); +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr); +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes); +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior); +static void deparseConstraint(DeparseState *state, Constraint *constraint); +static void deparseSchemaStmt(DeparseState *state, Node *node); +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item); +static void deparseAConst(DeparseState *state, A_Const *a_const); +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(DeparseState *state, Node *node); +static void deparseRuleActionStmt(DeparseState *state, Node *node); +static void deparseExplainableStmt(DeparseState *state, Node *node); +static void deparseStmt(DeparseState *state, Node *node); +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context); + +static void +removeTrailingSpaceFromStr(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static DeparseStatePart * +makeDeparseStatePart(DeparseState *state, DeparseStateNestingLevel *level, DeparsePartIndentMode indent_mode) +{ + DeparseStatePart *part = palloc(sizeof(DeparseStatePart)); + part->str = makeStringInfo(); + part->indent = level->base_indent; + if (indent_mode != DEPARSE_PART_NO_INDENT) + part->indent += state->opts.indent_size; + part->mergeable = indent_mode == DEPARSE_PART_INDENT_AND_MERGE; + return part; +} + +static void +freeDeparseStatePart(DeparseStatePart *part) +{ + pfree(part->str->data); + pfree(part->str); + pfree(part); +} + +// Returns current active part group, and initializes the first one (including an empty part) if needed +static DeparseStatePartGroup * +deparseGetCurrentPartGroup(DeparseState *state) +{ + DeparseStateNestingLevel *level = state->current; + if (level->part_groups) + return (DeparseStatePartGroup *) llast(level->part_groups); + + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, level, part_group->indent_mode)); + level->part_groups = lappend(level->part_groups, part_group); + return part_group; +} + +static DeparseStatePart * +deparseGetCurrentPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + return (DeparseStatePart *) llast(part_group->parts); +} + +static void +deparseMarkCurrentPartNonMergable(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + part->mergeable = false; +} + +static StringInfo deparseGetCurrentStringInfo(DeparseState *state) +{ + DeparseStatePart *part = deparseGetCurrentPart(state); + Assert(part != NULL); + return part->str; +} + +static void deparseAppendStringInfo(DeparseState *state, const char *fmt,...) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + int save_errno = errno; + + for (;;) + { + va_list args; + int needed; + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + needed = appendStringInfoVA(str, fmt, args); + va_end(args); + + if (needed == 0) + break; /* success */ + + /* Increase the buffer size and try again. */ + enlargeStringInfo(str, needed); + } +} + +static void deparseAppendStringInfoString(DeparseState *state, const char *s) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoString(str, s); +} + +static void deparseAppendStringInfoChar(DeparseState *state, char ch) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + appendStringInfoChar(str, ch); +} + +static void +removeTrailingSpace(DeparseState *state) +{ + StringInfo str = deparseGetCurrentStringInfo(state); + removeTrailingSpaceFromStr(str); +} + +static void +deparseRemoveTrailingEmptyPart(DeparseState *state) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + DeparseStatePart *last_part = deparseGetCurrentPart(state); + + if (last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + part_group->parts = list_delete_last(part_group->parts); + } +} + +static void +deparseAppendPart(DeparseState *state, bool deduplicate) +{ + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + + // Remove previous part if its empty and we deduplicate. We don't keep + // the existing part since it may have the wrong indent level or mode. + if (deduplicate) + deparseRemoveTrailingEmptyPart(state); + + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, part_group->indent_mode)); +} + +static void +deparseAppendCommaAndPart(DeparseState *state) +{ + if (state->opts.commas_start_of_line) + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, ", "); + } + else + { + deparseAppendStringInfoChar(state, ','); + deparseAppendPart(state, true); + } +} + +static void +deparseAppendPartGroup(DeparseState *state, const char *keyword, DeparsePartIndentMode indent_mode) +{ + DeparseStateNestingLevel *level = state->current; + DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); + + if (list_length(level->part_groups) > 0) + removeTrailingSpace(state); + + part_group->keyword = keyword; + part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, indent_mode)); + part_group->indent_mode = indent_mode; + + level->part_groups = lappend(level->part_groups, part_group); +} + +static void +deparseAppendCommentsIfNeeded(DeparseState *state, ParseLoc location) +{ + for (int i = 0; i < state->opts.comment_count; i++) + { + if (bms_is_member(i, state->emitted_comments)) + continue; + + PostgresDeparseComment *comment = state->opts.comments[i]; + if (comment->match_location > location) + continue; + + // Emit one less leading newline if we already emitted one for formatting reasons + int newlines_before_comment = comment->newlines_before_comment; + if (state->opts.pretty_print && newlines_before_comment > 0 && + deparseGetCurrentPartGroup(state)->keyword != NULL && + deparseGetCurrentStringInfo(state)->len == 0) + newlines_before_comment -= 1; + + for (int j = 0; j < newlines_before_comment; j++) + { + if (state->opts.pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + deparseAppendStringInfoString(state, comment->str); + + /* never merge comments with other parts */ + deparseMarkCurrentPartNonMergable(state); + + for (int j = 0; j < comment->newlines_after_comment; j++) + { + if (state->opts.pretty_print) + deparseAppendPart(state, false); + else + deparseAppendStringInfoChar(state, '\n'); + } + + state->emitted_comments = bms_add_member(state->emitted_comments, i); + } +} + +static void +deparseEmit(DeparseState *state, StringInfo str) +{ + ListCell *lc; + + /* If the last part is empty, drop it, so we don't confuse the newline output */ + DeparseStatePart *last_part = (DeparseStatePart *) llast(state->result_parts); + if (last_part && last_part->str->len == 0) + { + freeDeparseStatePart(last_part); + state->result_parts = list_delete_last(state->result_parts); + } + + foreach (lc, state->result_parts) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc); + bool last_part = list_cell_number(state->result_parts, lc) == list_length(state->result_parts) - 1; + + if (!state->opts.pretty_print && part->str->len > 0 && (part->str->data[0] == ')' || part->str->data[0] == ';')) + removeTrailingSpaceFromStr(str); + + if (state->opts.pretty_print) + { + for (int i = 0; i < part->indent; i++) + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, part->str->data); + removeTrailingSpaceFromStr(str); + + if (!last_part) + { + if (state->opts.pretty_print) + appendStringInfoChar(str, '\n'); + else if (str->data[str->len - 1] != '(') + appendStringInfoChar(str, ' '); + } + + freeDeparseStatePart(part); + } + list_free(state->result_parts); + state->result_parts = NIL; + + if (state->opts.pretty_print && state->opts.trailing_newline) + appendStringInfoChar(str, '\n'); +} + +static DeparseStateNestingLevel * +deparseStateIncreaseNestingLevel(DeparseState *state) +{ + DeparseStateNestingLevel *parent = state->current; + DeparseStateNestingLevel *level = palloc0(sizeof(DeparseStateNestingLevel)); + if (parent) + { + DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); + level->base_indent = parent->base_indent + state->opts.indent_size; + if (part_group->indent_mode != DEPARSE_PART_NO_INDENT) /* Indent again if parts next to us are also indented */ + level->base_indent += state->opts.indent_size; + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } + state->current = level; + return parent; +} + +static void +deparseStateDecreaseNestingLevel(DeparseState *state, DeparseStateNestingLevel *parent_level) +{ + ListCell *lc; + ListCell *lc2; + DeparseStateNestingLevel *level = state->current; + Assert(level != NULL); + + foreach (lc, level->part_groups) + { + DeparseStatePartGroup *part_group = (DeparseStatePartGroup *) lfirst(lc); + + /* Merge parts */ + if (part_group->indent_mode == DEPARSE_PART_INDENT_AND_MERGE && list_length(part_group->parts) > 1) + { + DeparseStatePart *target = (DeparseStatePart *) linitial(part_group->parts); + for_each_from (lc2, part_group->parts, 1) + { + DeparseStatePart *part = (DeparseStatePart *) lfirst(lc2); + removeTrailingSpaceFromStr(target->str); + if (target->mergeable && part->mergeable && + target->indent + target->str->len + 1 + part->str->len <= state->opts.max_line_length) + { + if (target->str->len > 0 && target->str->data[target->str->len - 1] != '(') + appendStringInfoChar(target->str, ' '); + appendStringInfoString(target->str, part->str->data); + freeDeparseStatePart(part); + part_group->parts = foreach_delete_current(part_group->parts, lc2); + } + else + { + target = part; + } + } + } + + if (part_group->keyword != NULL) + { + DeparseStatePart *target = makeDeparseStatePart(state, level, false); + appendStringInfoString(target->str, part_group->keyword); + part_group->parts = list_insert_nth(part_group->parts, 0, target); + + if (list_length(part_group->parts) == 2 || part_group->indent_mode == DEPARSE_PART_NO_INDENT) + { + DeparseStatePart *part = (DeparseStatePart *) lsecond(part_group->parts); + if (part->str->len > 0) + appendStringInfo(target->str, " %s", part->str->data); + freeDeparseStatePart(part); + part_group->parts = list_delete_nth_cell(part_group->parts, 1); + } + } + + if (parent_level) + { + DeparseStatePartGroup *parent_part_group = (DeparseStatePartGroup *) llast(parent_level->part_groups); + parent_part_group->parts = list_concat(parent_part_group->parts, part_group->parts); + } + else + { + // If its the top level, save as results instead + state->result_parts = list_concat(state->result_parts, part_group->parts); + } + + list_free(part_group->parts); + pfree(part_group); + } + list_free(level->part_groups); + pfree(level); + + state->current = parent_level; + + if (parent_level) + { + /* Make sure parent statement writes that follow are on their own line */ + deparseAppendPart(state, true); + + /* Parts with nested elements don't get merged, even if otherwise permitted */ + deparseMarkCurrentPartNonMergable(state); + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies, and modified to work with deparser + * state. + */ +static void +deparseStringLiteral(DeparseState *state, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + deparseAppendStringInfoChar(state, ESCAPE_STRING_SYNTAX); + deparseAppendStringInfoChar(state, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + deparseAppendStringInfoChar(state, ch); + deparseAppendStringInfoChar(state, ch); + } + deparseAppendStringInfoChar(state, '\''); +} + +// "any_name" in gram.y +static void deparseAnyName(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} +static void deparseAnyNameSkipFirst(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} +static void deparseAnyNameSkipLast(DeparseState *state, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + deparseAppendStringInfoChar(state, '.'); + } + } +} + +// "func_expr" in gram.y +static void deparseFuncExpr(DeparseState *state, Node *node, DeparseNodeContext context) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(state, castNode(FuncCall, node), context); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(state, castNode(XmlExpr, node), context); + break; + case T_XmlSerialize: + deparseXmlSerialize(state, castNode(XmlSerialize, node)); + break; + case T_JsonObjectAgg: + deparseJsonObjectAgg(state, castNode(JsonObjectAgg, node)); + break; + case T_JsonArrayAgg: + deparseJsonArrayAgg(state, castNode(JsonArrayAgg, node)); + break; + case T_JsonObjectConstructor: + deparseJsonObjectConstructor(state, castNode(JsonObjectConstructor, node)); + break; + case T_JsonArrayConstructor: + deparseJsonArrayConstructor(state, castNode(JsonArrayConstructor, node)); + break; + case T_JsonArrayQueryConstructor: + deparseJsonArrayQueryConstructor(state, castNode(JsonArrayQueryConstructor, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in func_expr: %d", + (int) nodeTag(node)); + break; + } +} + +static void deparseCExpr(DeparseState *state, Node *node); + +// "a_expr" in gram.y +static void deparseExpr(DeparseState *state, Node *node, DeparseNodeContext context) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_ColumnRef: + case T_A_Const: + case T_ParamRef: + case T_A_Indirection: + case T_CaseExpr: + case T_SubLink: + case T_A_ArrayExpr: + case T_RowExpr: + case T_GroupingFunc: + deparseCExpr(state, node); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CollateClause: + deparseCollateClause(state, castNode(CollateClause, node)); + break; + case T_A_Expr: + deparseAExpr(state, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_A_EXPR); + break; + case T_BoolExpr: + deparseBoolExpr(state, castNode(BoolExpr, node)); + break; + case T_NullTest: + deparseNullTest(state, castNode(NullTest, node)); + break; + case T_BooleanTest: + deparseBooleanTest(state, castNode(BooleanTest, node)); + break; + case T_JsonIsPredicate: + deparseJsonIsPredicate(state, castNode(JsonIsPredicate, node)); + break; + case T_SetToDefault: + deparseSetToDefault(state, castNode(SetToDefault, node)); + break; + case T_MergeSupportFunc: + deparseAppendStringInfoString(state, "merge_action() "); + break; + case T_JsonParseExpr: + deparseJsonParseExpr(state, castNode(JsonParseExpr, node)); + break; + case T_JsonScalarExpr: + deparseJsonScalarExpr(state, castNode(JsonScalarExpr, node)); + break; + case T_JsonSerializeExpr: + deparseJsonSerializeExpr(state, castNode(JsonSerializeExpr, node)); + break; + case T_JsonFuncExpr: + deparseJsonFuncExpr(state, castNode(JsonFuncExpr, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(state, node, context); + break; + default: + // Note that this is also the fallthrough for deparseBExpr and deparseCExpr + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr/c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "b_expr" in gram.y +static void deparseBExpr(DeparseState *state, Node *node) +{ + if (IsA(node, XmlExpr)) { + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE); + return; + } + + if (IsA(node, A_Expr)) { + A_Expr *a_expr = castNode(A_Expr, node); + // Other kinds are handled by "c_expr", with parens added around them + if (a_expr->kind == AEXPR_OP || a_expr->kind == AEXPR_DISTINCT || a_expr->kind == AEXPR_NOT_DISTINCT) { + deparseAExpr(state, a_expr, DEPARSE_NODE_CONTEXT_NONE); + return; + } + } + + if (IsA(node, BoolExpr)) { + BoolExpr *bool_expr = castNode(BoolExpr, node); + if (bool_expr->boolop == NOT_EXPR) { + deparseBoolExpr(state, bool_expr); + return; + } + } + + deparseCExpr(state, node); +} + +// "AexprConst" in gram.y +static void deparseAexprConst(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_A_Const: + deparseAConst(state, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + default: + elog(ERROR, "deparse: unpermitted node type in AexprConst: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(state, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(state, castNode(A_Const, node)); + break; + case T_ParamRef: + deparseParamRef(state, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(state, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(state, castNode(CaseExpr, node)); + break; + case T_SubLink: + deparseSubLink(state, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(state, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(state, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(state, castNode(GroupingFunc, node)); + break; + case T_FuncCall: + case T_SQLValueFunction: + case T_MinMaxExpr: + case T_CoalesceExpr: + case T_XmlExpr: + case T_XmlSerialize: + case T_JsonObjectAgg: + case T_JsonArrayAgg: + case T_JsonObjectConstructor: + case T_JsonArrayConstructor: + case T_JsonArrayQueryConstructor: + deparseFuncExpr(state, node, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + deparseAppendStringInfoChar(state, '('); + // Because we wrap this in parenthesis, the expression inside follows "a_expr" parser rules + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(DeparseState *state, char *s) +{ + deparseAppendStringInfoString(state, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(DeparseState *state, char *s) +{ + deparseAppendStringInfoString(state, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(DeparseState *state, Node *node) +{ + deparseAppendStringInfo(state, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(DeparseState *state, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + deparseAppendStringInfoChar(state, '.'); + deparseColLabel(state, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + deparseAppendStringInfoString(state, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(state, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(DeparseState *state, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(state, role_spec); + if (lnext(roles, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(DeparseState *state, Node *node) +{ + deparseTypeName(state, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(DeparseState *state, union ValUnion *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + deparseAppendStringInfo(state, "%d", value->ival.ival); + break; + case T_Float: + deparseAppendStringInfoString(state, value->sval.sval); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(state, (union ValUnion *) lfirst(lc)); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(DeparseState *state, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + deparseAppendStringInfoString(state, "AS "); + deparseSimpleTypename(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + deparseAppendStringInfoString(state, "CACHE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + deparseAppendStringInfoString(state, "INCREMENT "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "MAXVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "MINVALUE "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + deparseAppendStringInfoString(state, "OWNED BY "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + deparseAppendStringInfoString(state, "SEQUENCE NAME "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + deparseAppendStringInfoString(state, "START "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(DeparseState *state, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(state, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseSeqOptList(state, options); + deparseAppendStringInfoChar(state, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(DeparseState *state, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + deparseAppendStringInfoString(state, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(DeparseState *state, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(op)))); + deparseAppendStringInfoChar(state, '.'); + deparseAppendStringInfoString(state, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + deparseAppendStringInfoString(state, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(DeparseState *state, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + deparseAppendStringInfoString(state, strVal(linitial(op))); + } + else + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(DeparseState *state, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + deparseAppendStringInfoString(state, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + deparseAppendStringInfoString(state, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + deparseAppendStringInfoString(state, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + deparseAppendStringInfoString(state, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + deparseAppendStringInfoString(state, strVal(linitial(op))); + } + else + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, op); + deparseAppendStringInfoString(state, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(DeparseState *state, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + deparseAppendStringInfoString(state, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(DeparseState *state, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(state, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + deparseAppendStringInfoString(state, "OPERATOR("); + deparseAnyOperator(state, l); + deparseAppendStringInfoChar(state, ')'); + } + else if (list_length(l) == 1) + { + deparseAppendStringInfoString(state, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(state, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + deparseAppendStringInfoString(state, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + deparseAppendStringInfoString(state, s); + } + else // Sconst + { + deparseStringLiteral(state, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoChar(state, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + deparseAppendStringInfoString(state, " = "); + deparseDefArg(state, def_elem->arg, false); + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(DeparseState *state, List *options) +{ + if (list_length(options) > 0) + { + deparseAppendStringInfoString(state, "WITH "); + deparseDefinition(state, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + deparseAppendStringInfoString(state, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ")"); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + deparseAppendStringInfoString(state, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + deparseAppendStringInfoString(state, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + deparseAppendStringInfoString(state, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + deparseAppendStringInfoString(state, "COST "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + deparseAppendStringInfoString(state, "ROWS "); + deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + deparseAppendStringInfoString(state, "SUPPORT "); + deparseAnyName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(state, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + deparseAppendStringInfoString(state, "PARALLEL "); + deparseAppendStringInfoString(state, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(DeparseState *state, const char *val) +{ + if (strlen(val) == 0) + deparseAppendStringInfoString(state, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(state, val); + else + deparseAppendStringInfoString(state, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + deparseAppendStringInfoString(state, "$$"); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, "$$"); + } + else + { + deparseStringLiteral(state, strval); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(DeparseState *state, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + deparseAppendStringInfoString(state, "AS "); + deparseFuncAs(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoString(state, "TRANSFORM "); + foreach (lc, l) + { + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + deparseAppendStringInfoString(state, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(state, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + deparseAppendStringInfoString(state, "ADD "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoChar(state, ' '); + deparseStringLiteral(state, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + deparseAppendStringInfoString(state, "DROP "); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(DeparseState *state, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(state, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + deparseAppendStringInfoChar(state, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(DeparseState *state, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(state, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + deparseAppendStringInfoChar(state, '('); + if (linitial(object_with_args->objargs) == NULL) + deparseAppendStringInfoString(state, "NONE"); + else + deparseTypeName(state, castNode(TypeName, linitial(object_with_args->objargs))); + deparseAppendStringInfoString(state, ", "); + if (lsecond(object_with_args->objargs) == NULL) + deparseAppendStringInfoString(state, "NONE"); + else + deparseTypeName(state, castNode(TypeName, lsecond(object_with_args->objargs))); + deparseAppendStringInfoChar(state, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(DeparseState *state, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + deparseAppendStringInfoChar(state, '('); + if (args == NULL) + { + deparseAppendStringInfoChar(state, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + deparseAppendStringInfoString(state, ", "); + } + + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + deparseAppendStringInfoString(state, " ORDER BY "); + deparseFunctionParameter(state, castNode(FunctionParameter, llast(args))); + } + } + deparseAppendStringInfoChar(state, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(state, object_with_args->objname); + + deparseAppendStringInfoChar(state, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + deparseAppendStringInfoChar(state, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(state, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(DeparseState *state, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(DeparseState *state, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + deparseAppendStringInfoString(state, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + deparseAppendStringInfoString(state, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(DeparseState *state, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(DeparseState *state, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + deparseAppendStringInfoChar(state, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(DeparseState *state, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(DeparseState *state, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(DeparseState *state, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + deparseAppendStringInfoString(state, "TRUE"); + else if (strcmp(s, "false") == 0) + deparseAppendStringInfoString(state, "FALSE"); + else if (strcmp(s, "on") == 0) + deparseAppendStringInfoString(state, "ON"); + else if (strcmp(s, "off") == 0) + deparseAppendStringInfoString(state, "OFF"); + else + deparseNonReservedWordOrSconst(state, s); +} + +static void deparseOptBoolean(DeparseState *state, Node *node) +{ + if (node == NULL) + { + return; + } + + switch (nodeTag(node)) + { + case T_String: + deparseAppendStringInfo(state, " %s", strVal(node)); + break; + case T_Integer: + deparseAppendStringInfo(state, " %d", intVal(node)); + break; + case T_Boolean: + deparseAppendStringInfo(state, " %s", boolVal(node) ? "TRUE" : "FALSE"); + break; + default: + Assert(false); + break; + } +} + +bool optBooleanValue(Node *node) +{ + if (node == NULL) + { + return true; + } + + switch (nodeTag(node)) + { + case T_String: { + // Longest valid string is "off\0" + char lower[4]; + strncpy(lower, strVal(node), 4); + lower[3] = 0; + + if (strcmp(lower, "on") == 0) { + return true; + } else if (strcmp(lower, "off") == 0) { + return false; + } + + // No sane way to handle this. + return false; + } + case T_Integer: + return intVal(node) != 0; + case T_Boolean: + return boolVal(node); + default: + Assert(false); + return false; + } +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(DeparseState *state, char *s) +{ + deparseColId(state, s); +} + +// "var_list" +static void deparseVarList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(state, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(state, (union ValUnion *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(state, strVal(&a_const->val)); + else + Assert(false); + } + else if (IsA(lfirst(lc), TypeCast)) + { + deparseTypeCast(state, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + deparseAppendStringInfoString(state, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + deparseAppendStringInfoString(state, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + deparseAppendStringInfoString(state, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + deparseAppendStringInfoString(state, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + deparseAppendStringInfoString(state, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + deparseAppendStringInfoString(state, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + deparseAppendStringInfoString(state, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + deparseAppendStringInfoString(state, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + deparseAppendStringInfoString(state, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + deparseAppendStringInfoString(state, "RESTART "); + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + deparseAppendStringInfoString(state, "SET GENERATED "); + if (def_elem->arg == NULL) + elog(ERROR, "deparse: missing argument for identity generation specification"); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + deparseAppendStringInfoString(state, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + deparseAppendStringInfoString(state, "BY DEFAULT"); + else + Assert(false); + } + else + { + deparseAppendStringInfoString(state, "SET "); + deparseSeqOptElem(state, def_elem); + } + if (lnext(l, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoChar(state, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(def_elem->defnamespace)); + deparseAppendStringInfoChar(state, '.'); + } + if (def_elem->defname != NULL) + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + deparseAppendStringInfoChar(state, '='); + if (def_elem->arg != NULL) + deparseDefArg(state, def_elem->arg, false); + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "WITH "); + deparseRelOptions(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(state, castNode(ColumnRef, res_target->val)); + else + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (res_target->name != NULL) { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + deparseOptIndirection(state, res_target->indirection, 0); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (res_target->name != NULL) + { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + + if (res_target->name != NULL) + { + deparseAppendStringInfoString(state, " AS "); + deparseAppendStringInfoString(state, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(state, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(state, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(state, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(state, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(state, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(state, castNode(JoinExpr, node)); + break; + case T_JsonTable: + deparseJsonTable(state, castNode(JsonTable, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(state, lfirst(lc)); + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendPartGroup(state, "FROM", DEPARSE_PART_INDENT); + deparseFromList(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(DeparseState *state, Node *node) +{ + if (node != NULL) + { + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "where_or_current_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereOrCurrentClause(DeparseState *state, Node *node) +{ + if (node == NULL) + return; + + deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); + + if (IsA(node, CurrentOfExpr)) { + CurrentOfExpr *current_of_expr = castNode(CurrentOfExpr, node); + deparseAppendStringInfoString(state, "CURRENT OF "); + deparseAppendStringInfoString(state, quote_identifier(current_of_expr->cursor_name)); + } else { + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + deparseAppendStringInfoChar(state, ' '); +} + +// "group_by_list" in gram.y +static void deparseGroupByList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(state, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (lnext(l, lc)) + deparseAppendCommaAndPart(state); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(DeparseState *state, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(state, res_target->name); + deparseOptIndirection(state, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(state, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(state, strVal(lfirst(lc))); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "opt_sort_clause" and "json_array_aggregate_order_by_clause_opt" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(DeparseState *state, List *l, DeparseNodeContext context) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendPartGroup(state, "ORDER BY", DEPARSE_PART_INDENT_AND_MERGE); + else + deparseAppendStringInfoString(state, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(state, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + { + if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) + deparseAppendCommaAndPart(state); + else + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(DeparseState *state, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + deparseAppendStringInfoString(state, named_arg_expr->name); + deparseAppendStringInfoString(state, " := "); + deparseExpr(state, (Node *) named_arg_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + } + else + { + deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(DeparseState *state, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + deparseAppendCommaAndPart(state); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + deparseAppendStringInfoString(state, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(state, castNode(ResTarget, lfirst(lc2))); + if ((foreach_current_index(lc2) - foreach_current_index(lc)) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") = "); + deparseExpr(state, r->source, DEPARSE_NODE_CONTEXT_A_EXPR); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(state, res_target); + deparseAppendStringInfoString(state, " = "); + deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(DeparseState *state, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(state, castNode(FuncCall, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); + break; + case T_XmlSerialize: + deparseXmlSerialize(state, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, l); + deparseAppendStringInfoChar(state, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(DeparseState *state, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(state, index_elem->name); + deparseAppendStringInfoChar(state, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + // Simple function calls can be written without wrapping parens + case T_FuncCall: // func_application + case T_SQLValueFunction: // func_expr_common_subexpr + case T_CoalesceExpr: // func_expr_common_subexpr + case T_MinMaxExpr: // func_expr_common_subexpr + case T_XmlExpr: // func_expr_common_subexpr + case T_XmlSerialize: // func_expr_common_subexpr + deparseFuncExprWindowless(state, index_elem->expr); + deparseAppendStringInfoString(state, " "); + break; + default: + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, index_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(state, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(state, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(state, index_elem->opclassopts); + + deparseAppendStringInfoChar(state, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + deparseAppendStringInfoString(state, "ASC "); + break; + case SORTBY_DESC: + deparseAppendStringInfoString(state, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + deparseAppendStringInfoString(state, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + deparseAppendStringInfoString(state, "NULLS LAST "); + break; + } + + removeTrailingSpace(state); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(DeparseState *state, List *l) +{ + if (list_length(l) > 0) + { + deparseAppendStringInfoString(state, "INHERITS ("); + deparseQualifiedNameList(state, l); + deparseAppendStringInfoString(state, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(DeparseState *state, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(state, objs); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseQualifiedNameList(state, objs); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseNameList(state, objs); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "FOREIGN SERVER "); + deparseNameList(state, objs); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypesList(state, objs); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseNameList(state, objs); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyNameList(state, objs); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNameList(state, objs); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnlyList(state, objs); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseNameList(state, objs); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyNameList(state, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "ALL TABLES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(state, objs); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ALL ROUTINES IN SCHEMA "); + deparseNameList(state, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLES"); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCES"); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPES"); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(DeparseState *state, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(state, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(DeparseState *state, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + deparseAppendStringInfoString(state, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(state, def_elem->defname); + + deparseAppendStringInfoChar(state, ' '); + + if (def_elem->arg == NULL) + deparseAppendStringInfoString(state, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(state, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + + if (lnext(l, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(DeparseState *state, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(state, def_elem->defname); + + if (def_elem->arg != NULL) + { + deparseAppendStringInfoChar(state, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } +} + +static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + bool need_parens = context == DEPARSE_NODE_CONTEXT_SELECT_SETOP && ( + list_length(stmt->sortClause) > 0 || + stmt->limitOffset != NULL || + stmt->limitCount != NULL || + list_length(stmt->lockingClause) > 0 || + stmt->withClause != NULL || + stmt->op != SETOP_NONE); + DeparseStateNestingLevel *parent_level = NULL; + + if (need_parens) + { + deparseAppendPart(state, true); + deparseAppendStringInfoChar(state, '('); + } + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + parent_level = deparseStateIncreaseNestingLevel(state); + + if (stmt->withClause) + { + deparseWithClause(state, stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + deparseAppendPartGroup(state, "VALUES", DEPARSE_PART_INDENT_AND_MERGE); + + foreach(lc, stmt->valuesLists) + { + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ')'); + if (lnext(stmt->valuesLists, lc)) + deparseAppendCommaAndPart(state); + } + deparseAppendStringInfoChar(state, ' '); + break; + } + + deparseAppendPartGroup(state, "SELECT", DEPARSE_PART_INDENT_AND_MERGE); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + deparseMarkCurrentPartNonMergable(state); + deparseAppendStringInfoString(state, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + deparseAppendStringInfoString(state, "ON ("); + deparseExprList(state, stmt->distinctClause); + deparseAppendStringInfoString(state, ") "); + } + deparseAppendPart(state, true); + } + + deparseTargetList(state, stmt->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->intoClause != NULL) + { + deparseAppendPartGroup(state, "INTO", DEPARSE_PART_INDENT); + deparseOptTemp(state, stmt->intoClause->rel->relpersistence); + deparseIntoClause(state, stmt->intoClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseFromClause(state, stmt->fromClause); + deparseWhereClause(state, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + deparseAppendPartGroup(state, "GROUP BY", DEPARSE_PART_INDENT_AND_MERGE); + if (stmt->groupDistinct) + deparseAppendStringInfoString(state, "DISTINCT "); + deparseGroupByList(state, stmt->groupClause); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->havingClause != NULL) + { + deparseAppendPartGroup(state, "HAVING", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->havingClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (stmt->windowClause != NULL) + { + deparseAppendPartGroup(state, "WINDOW", DEPARSE_PART_INDENT); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + deparseAppendStringInfoString(state, window_def->name); + deparseAppendStringInfoString(state, " AS "); + deparseWindowDef(state, window_def); + if (lnext(stmt->windowClause, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + deparseSelectStmt(state, stmt->larg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); + switch (stmt->op) + { + case SETOP_UNION: + if (stmt->all) + deparseAppendPartGroup(state, "UNION ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "UNION", DEPARSE_PART_NO_INDENT); + break; + case SETOP_INTERSECT: + if (stmt->all) + deparseAppendPartGroup(state, "INTERSECT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "INTERSECT", DEPARSE_PART_NO_INDENT); + break; + case SETOP_EXCEPT: + if (stmt->all) + deparseAppendPartGroup(state, "EXCEPT ALL", DEPARSE_PART_NO_INDENT); + else + deparseAppendPartGroup(state, "EXCEPT", DEPARSE_PART_NO_INDENT); + break; + default: + Assert(false); + } + deparseAppendPart(state, true); + deparseSelectStmt(state, stmt->rarg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); + deparseAppendStringInfoChar(state, ' '); + } + break; + } + + deparseOptSortClause(state, stmt->sortClause, DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + deparseAppendPartGroup(state, "LIMIT", DEPARSE_PART_INDENT); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseAppendStringInfoString(state, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) + deparseAppendStringInfoString(state, "ALL"); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseCExpr(state, stmt->limitCount); + else + deparseExpr(state, stmt->limitCount, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + + deparseAppendStringInfoChar(state, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + deparseAppendStringInfoString(state, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + deparseAppendPartGroup(state, "OFFSET", DEPARSE_PART_INDENT); + deparseExpr(state, stmt->limitOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(state, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + deparseAppendStringInfoString(state, " "); + } + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); + + /* Note that parent_level can be NULL, so we repeat the full if condition here */ + if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) + deparseStateDecreaseNestingLevel(state, parent_level); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseIntoClause(DeparseState *state, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(state, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, into_clause->colNames); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + + if (into_clause->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->accessMethod)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseOptWith(state, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + deparseAppendStringInfoString(state, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(into_clause->tableSpaceName)); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ONLY "); + + if (range_var->catalogname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(range_var->catalogname)); + deparseAppendStringInfoChar(state, '.'); + } + + if (range_var->schemaname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(range_var->schemaname)); + deparseAppendStringInfoChar(state, '.'); + } + + Assert(range_var->relname != NULL); + deparseAppendStringInfoString(state, quote_identifier(range_var->relname)); + deparseAppendStringInfoChar(state, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_var->alias); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt) +{ + PostgresDeparseOpts opts; + MemSet(&opts, 0, sizeof(PostgresDeparseOpts)); // zero initialized means pretty print = false + deparseRawStmtOpts(str, raw_stmt, opts); +} + +void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts opts) +{ + DeparseState *state = NULL; + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + state = palloc0(sizeof(DeparseState)); + state->opts = opts; + if (state->opts.indent_size == 0) + state->opts.indent_size = 4; + if (state->opts.max_line_length == 0) + state->opts.max_line_length = 80; + + /* Check for any comments at the start of the statement */ + if (state->opts.comment_count > 0) + { + /* + * Filter out comments that are placed before this statement starts, this + * avoids emitting comments multiple times in multi-statement queries. + */ + for (int i = 0; i < state->opts.comment_count; i++) + { + if (state->opts.comments[i]->match_location < raw_stmt->stmt_location) + state->emitted_comments = bms_add_member(state->emitted_comments, i); + } + + deparseStateIncreaseNestingLevel(state); + deparseAppendCommentsIfNeeded(state, raw_stmt->stmt_location); + deparseRemoveTrailingEmptyPart(state); + deparseStateDecreaseNestingLevel(state, NULL); + } + + deparseStmt(state, raw_stmt->stmt); + + deparseEmit(state, str); + + bms_free(state->emitted_comments); + pfree(state); +} + +static void deparseAlias(DeparseState *state, Alias *alias) +{ + deparseAppendStringInfoString(state, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, alias->colnames); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseAConst(DeparseState *state, A_Const *a_const) +{ + union ValUnion *val = a_const->isnull ? NULL : &a_const->val; + deparseAppendCommentsIfNeeded(state, a_const->location); + deparseValue(state, val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "OVERLAY("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PLACING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + deparseAppendStringInfoString(state, "SUBSTRING("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(func_call->args) == 3) + { + deparseAppendStringInfoString(state, " FOR "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + deparseAppendStringInfoString(state, "POSITION("); + deparseBExpr(state, lsecond(func_call->args)); + deparseAppendStringInfoString(state, " IN "); + deparseBExpr(state, linitial(func_call->args)); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "overlay("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " placing "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " from "); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + deparseAppendStringInfoString(state, "collation for ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + deparseAppendStringInfoString(state, "extract ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + + deparseAppendStringInfoString(state, "overlaps "); + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + deparseAppendStringInfoString(state, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + deparseAppendStringInfoString(state, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + deparseAppendStringInfoString(state, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + deparseAppendStringInfoString(state, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FROM "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) > 0 && + list_length(func_call->args) <= 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + Expr* e; + bool isLocal = list_length(func_call->args) == 1; + + if (isLocal) + e = linitial(func_call->args); + else + e = lsecond(func_call->args); + + // If we're not inside an a_expr context, we must add wrapping parenthesis around the AT ... syntax + if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { + deparseAppendStringInfoChar(state, '('); + } + + if (IsA(e, A_Expr)) { + deparseAppendStringInfoChar(state, '('); + } + + deparseExpr(state, (Node*) e, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (IsA(e, A_Expr)) { + deparseAppendStringInfoChar(state, ')'); + } + + if (isLocal) + deparseAppendStringInfoString(state, " AT LOCAL"); + else { + deparseAppendStringInfoString(state, " AT TIME ZONE "); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + + if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { + deparseAppendStringInfoChar(state, ')'); + } + + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + deparseAppendStringInfoString(state, "normalize ("); + + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(func_call->args) == 2) + { + deparseAppendStringInfoString(state, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + deparseAppendStringInfoString(state, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + deparseAppendStringInfoString(state, "xmlexists ("); + deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "system_user") == 0) + { + deparseAppendStringInfoString(state, "SYSTEM_USER"); + return; + } + + deparseFuncName(state, func_call->funcname); + deparseAppendStringInfoChar(state, '('); + + if (func_call->agg_distinct) + deparseAppendStringInfoString(state, "DISTINCT "); + + if (func_call->agg_star) + { + deparseAppendStringInfoChar(state, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + deparseAppendStringInfoString(state, "VARIADIC "); + deparseFuncArgExpr(state, lfirst(lc)); + if (lnext(func_call->args, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoChar(state, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); + } + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + deparseAppendStringInfoString(state, "WITHIN GROUP ("); + deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + } + + if (func_call->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, func_call->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (func_call->over) + { + deparseAppendStringInfoString(state, "OVER "); + if (func_call->over->name) + deparseAppendStringInfoString(state, func_call->over->name); + else + deparseWindowDef(state, func_call->over); + } + + removeTrailingSpace(state); +} + +static void deparseWindowDef(DeparseState *state, WindowDef* window_def) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + // The parent node is responsible for outputting window_def->name + + // Special case completely empty window clauses and return early + if (!window_def->refname && list_length(window_def->partitionClause) == 0 && + list_length(window_def->orderClause) == 0 && + !(window_def->frameOptions & FRAMEOPTION_NONDEFAULT)) + { + deparseAppendStringInfoString(state, "()"); + return; + } + + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); + + if (window_def->refname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(window_def->refname)); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + deparseAppendStringInfoString(state, "PARTITION BY "); + deparseExprList(state, window_def->partitionClause); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); + deparseAppendPart(state, true); + deparseOptSortClause(state, window_def->orderClause, DEPARSE_NODE_CONTEXT_NONE); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + deparseAppendPartGroup(state, NULL, DEPARSE_PART_NO_INDENT); + if (window_def->frameOptions & FRAMEOPTION_RANGE) + deparseAppendStringInfoString(state, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + deparseAppendStringInfoString(state, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + deparseAppendStringInfoString(state, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + deparseAppendStringInfoString(state, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + deparseAppendStringInfoString(state, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + deparseAppendStringInfoString(state, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + deparseAppendStringInfoString(state, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + deparseAppendStringInfoString(state, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + deparseAppendStringInfoString(state, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + deparseAppendStringInfoString(state, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + deparseAppendStringInfoString(state, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + deparseAppendStringInfoString(state, "EXCLUDE TIES "); + } + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + deparseAppendCommentsIfNeeded(state, column_ref->location); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(state, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(state, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(state, column_ref->fields, 1); +} + +static void deparseSubLink(DeparseState *state, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + deparseAppendStringInfoString(state, "EXISTS ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ALL_SUBLINK: + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ALL ("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ANY_SUBLINK: + deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + if (list_length(sub_link->operName) > 0) + { + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, sub_link->operName); + deparseAppendStringInfoString(state, " ANY "); + } + else + { + deparseAppendStringInfoString(state, " IN "); + } + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + deparseAppendStringInfoString(state, "("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + deparseAppendStringInfoString(state, "ARRAY("); + deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +// Checks whether a node needs parens when used in a "b_expr" context (because the node is handled by the "a_expr" rule in gram.y) +static bool +needsParensAsBExpr(Node *node) +{ + if (node == NULL) + return false; + return IsA(node, BoolExpr) || IsA(node, BooleanTest) || IsA(node, NullTest) || IsA(node, A_Expr); +} + +// This handles "A_Expr" parse tree objects, which are a subset of the rules in "a_expr" (handled by deparseExpr) +static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = needsParensAsBExpr(a_expr->lexpr); + bool need_rexpr_parens = needsParensAsBExpr(a_expr->rexpr); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + } + deparseQualOp(state, a_expr->name); + if (a_expr->rexpr != NULL) + { + deparseAppendStringInfoChar(state, ' '); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, ')'); + } + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ANY("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseSubqueryOp(state, a_expr->name); + deparseAppendStringInfoString(state, " ALL("); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->lexpr, context); + if (need_lexpr_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoString(state, " IS DISTINCT FROM "); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, a_expr->rexpr, context); + if (need_rexpr_parens) + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, " IS NOT DISTINCT FROM "); + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseAppendStringInfoString(state, "NULLIF("); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, a_expr->rexpr, context); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "=") == 0) { + deparseAppendStringInfoString(state, "IN "); + } else if (strcmp(name, "<>") == 0) { + deparseAppendStringInfoString(state, "NOT IN "); + } else { + Assert(false); + } + deparseAppendStringInfoChar(state, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(state, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(state, castNode(List, a_expr->rexpr)); + deparseAppendStringInfoChar(state, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~") == 0) { + deparseAppendStringInfoString(state, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + deparseAppendStringInfoString(state, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~*") == 0) { + deparseAppendStringInfoString(state, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + deparseAppendStringInfoString(state, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(state, a_expr->rexpr, context); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~") == 0) { + deparseAppendStringInfoString(state, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + deparseAppendStringInfoString(state, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(state, linitial(n->args), context); + if (list_length(n->args) == 2) + { + deparseAppendStringInfoString(state, " ESCAPE "); + deparseExpr(state, lsecond(n->args), context); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(state, a_expr->lexpr, context); + deparseAppendStringInfoChar(state, ' '); + deparseAppendStringInfoString(state, strVal(linitial(a_expr->name))); + deparseAppendStringInfoChar(state, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(state, lfirst(lc), context); + if (lnext(castNode(List, a_expr->rexpr), lc)) + deparseAppendStringInfoString(state, " AND "); + } + return; + } +} + +static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + if (lnext(bool_expr->args, lc)) + { + deparseAppendPart(state, true); + deparseAppendStringInfoString(state, "AND "); + } + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + if (lnext(bool_expr->args, lc)) + deparseAppendStringInfoString(state, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + deparseAppendStringInfoString(state, "NOT "); + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, linitial(bool_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + return; + } +} + +static void deparseAStar(DeparseState *state, A_Star *a_star) +{ + deparseAppendStringInfoChar(state, '*'); +} + +static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, collate_clause->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + } + deparseAppendStringInfoString(state, "COLLATE "); + deparseAnyName(state, collate_clause->collname); +} + +// "sortby" in gram.y +static void deparseSortBy(DeparseState *state, SortBy* sort_by) +{ + deparseExpr(state, sort_by->node, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + deparseAppendStringInfoString(state, "ASC "); + break; + case SORTBY_DESC: + deparseAppendStringInfoString(state, "DESC "); + break; + case SORTBY_USING: + deparseAppendStringInfoString(state, "USING "); + deparseQualOp(state, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + deparseAppendStringInfoString(state, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + deparseAppendStringInfoString(state, "NULLS LAST "); + break; + } + + removeTrailingSpace(state); +} + +static void deparseParamRef(DeparseState *state, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + deparseAppendStringInfoChar(state, '?'); + } else { + deparseAppendStringInfo(state, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + deparseAppendStringInfoString(state, "current_date"); + break; + case SVFOP_CURRENT_TIME: + deparseAppendStringInfoString(state, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + deparseAppendStringInfoString(state, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + deparseAppendStringInfoString(state, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + deparseAppendStringInfoString(state, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + deparseAppendStringInfoString(state, "localtime"); + break; + case SVFOP_LOCALTIME_N: + deparseAppendStringInfoString(state, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + deparseAppendStringInfoString(state, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + deparseAppendStringInfoString(state, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + deparseAppendStringInfoString(state, "current_role"); + break; + case SVFOP_CURRENT_USER: + deparseAppendStringInfoString(state, "current_user"); + break; + case SVFOP_USER: + deparseAppendStringInfoString(state, "user"); + break; + case SVFOP_SESSION_USER: + deparseAppendStringInfoString(state, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + deparseAppendStringInfoString(state, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + deparseAppendStringInfoString(state, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + deparseAppendStringInfo(state, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(DeparseState *state, WithClause *with_clause) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "WITH", DEPARSE_PART_NO_INDENT); + if (with_clause->recursive) + deparseAppendStringInfoString(state, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(state, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + deparseAppendStringInfoString(state, ", "); + } + + removeTrailingSpace(state); +} + +// "joined_table" in gram.y +static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + deparseAppendStringInfoChar(state, '('); + + deparseTableRef(state, join_expr->larg); + deparseAppendPart(state, true); + + if (join_expr->isNatural) + deparseAppendStringInfoString(state, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + deparseAppendStringInfoString(state, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + deparseAppendStringInfoString(state, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + deparseAppendStringInfoString(state, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + deparseAppendStringInfoString(state, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_RIGHT_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + deparseAppendStringInfoString(state, "JOIN "); + + if (need_rarg_parens) + deparseAppendStringInfoChar(state, '('); + deparseTableRef(state, join_expr->rarg); + if (need_rarg_parens) + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + + if (join_expr->quals != NULL) + { + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, join_expr->quals, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + deparseAppendStringInfoString(state, "USING ("); + deparseNameList(state, join_expr->usingClause); + deparseAppendStringInfoString(state, ") "); + + if (join_expr->join_using_alias) + { + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoString(state, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + deparseAppendStringInfoString(state, ") "); + + if (join_expr->alias != NULL) + deparseAlias(state, join_expr->alias); + + removeTrailingSpace(state); +} + +static void deparseCTESearchClause(DeparseState *state, CTESearchClause *search_clause) +{ + deparseAppendStringInfoString(state, " SEARCH "); + if (search_clause->search_breadth_first) + deparseAppendStringInfoString(state, "BREADTH "); + else + deparseAppendStringInfoString(state, "DEPTH "); + + deparseAppendStringInfoString(state, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(state, search_clause->search_col_list); + + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(search_clause->search_seq_column)); +} + +// "opt_cycle_clause" in gram.y +static void deparseCTECycleClause(DeparseState *state, CTECycleClause *cycle_clause) +{ + deparseAppendStringInfoString(state, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(state, cycle_clause->cycle_col_list); + + deparseAppendStringInfoString(state, " SET "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + deparseAppendStringInfoString(state, " TO "); + deparseAexprConst(state, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + deparseAppendStringInfoString(state, " DEFAULT "); + deparseAexprConst(state, cycle_clause->cycle_mark_default); + } + + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte) +{ + deparseAppendCommentsIfNeeded(state, cte->location); + + deparseColId(state, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, cte->aliascolnames); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + deparseAppendStringInfoString(state, "MATERIALIZED "); + break; + case CTEMaterializeNever: + deparseAppendStringInfoString(state, "NOT MATERIALIZED "); + break; + } + + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, cte->ctequery); + deparseAppendStringInfoChar(state, ')'); + + if (cte->search_clause) + deparseCTESearchClause(state, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(state, cte->cycle_clause); +} + +static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + deparseAppendStringInfoChar(state, '('); + deparseSelectStmt(state, castNode(SelectStmt, range_subselect->subquery), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ')'); + + if (range_subselect->alias != NULL) + { + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, range_subselect->alias); + } +} + +static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + if (range_func->is_rowsfrom) + { + deparseAppendStringInfoString(state, "ROWS FROM "); + deparseAppendStringInfoChar(state, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(state, linitial(lfunc)); + deparseAppendStringInfoChar(state, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + deparseAppendStringInfoString(state, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + if (lnext(range_func->functions, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(state, linitial(linitial(range_func->functions))); + } + deparseAppendStringInfoChar(state, ' '); + + if (range_func->ordinality) + deparseAppendStringInfoString(state, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(state, range_func->alias); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + deparseAppendStringInfoString(state, "AS "); + deparseAppendStringInfoChar(state, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ARRAY["); + deparseExprList(state, array_expr->elements); + deparseAppendStringInfoChar(state, ']'); +} + +static void deparseRowExpr(DeparseState *state, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + deparseAppendStringInfoString(state, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + deparseAppendStringInfoString(state, "("); + deparseExprList(state, row_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context) +{ + bool need_parens = needsParensAsBExpr(type_cast->arg); + + Assert(type_cast->typeName != NULL); + + if (context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) + { + deparseAppendStringInfoString(state, "CAST("); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, type_cast->typeName); + deparseAppendStringInfoChar(state, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + deparseAppendStringInfoString(state, "char "); + deparseAConst(state, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + deparseAppendStringInfoString(state, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + deparseAppendStringInfoString(state, "false"); + return; + } + } + else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) + { + deparseAppendStringInfoString(state, "interval "); + deparseAConst(state, a_const); + deparseIntervalTypmods(state, type_cast->typeName); + return; + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + deparseAppendStringInfoString(state, " point "); + deparseAConst(state, a_const); + return; + } + } + + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_NONE /* could be either a_expr or b_expr (we could pass this down, but that'd require two kinds of contexts most likely) */); + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + deparseAppendStringInfoString(state, "::"); + deparseTypeName(state, type_cast->typeName); +} + +static void deparseTypeName(DeparseState *state, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + deparseAppendStringInfoString(state, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + deparseAppendStringInfoString(state, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + deparseAppendStringInfoString(state, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + deparseAppendStringInfoString(state, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + deparseAppendStringInfoString(state, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + deparseAppendStringInfoString(state, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + deparseAppendStringInfoString(state, "int"); + } + else if (strcmp(name, "int8") == 0) + { + deparseAppendStringInfoString(state, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + deparseAppendStringInfoString(state, "real"); + } + else if (strcmp(name, "float8") == 0) + { + deparseAppendStringInfoString(state, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + deparseAppendStringInfoString(state, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + deparseAppendStringInfoString(state, "time "); + if (list_length(type_name->typmods) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + deparseAppendStringInfoString(state, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + deparseAppendStringInfoString(state, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + deparseAppendStringInfoString(state, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + deparseAppendStringInfoString(state, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + deparseAppendStringInfoString(state, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + deparseAppendStringInfoString(state, "interval"); + deparseIntervalTypmods(state, type_name); + + skip_typmods = true; + } + else + { + deparseAppendStringInfoString(state, "pg_catalog."); + deparseAppendStringInfoString(state, name); + } + } + else + { + deparseAnyName(state, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(state, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(state, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(state, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + deparseAppendStringInfoChar(state, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(state, lfirst(lc)); + deparseAppendStringInfoChar(state, ']'); + } + + if (type_name->pct_type) + deparseAppendStringInfoString(state, "%type"); +} + +// Handle typemods for Interval types separately +// so that they can be applied appropriately for different contexts. +// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` +// the `INTERVAL` keyword is specified first. +// In all other contexts, intervals use the `'x'::interval` style. +static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name) +{ + const char *name = strVal(lsecond(type_name->names)); + Assert(strcmp(name, "interval") == 0); + Assert(list_length(type_name->typmods) >= 1); + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + deparseAppendStringInfoString(state, " year"); + break; + case INTERVAL_MASK(MONTH): + deparseAppendStringInfoString(state, " month"); + break; + case INTERVAL_MASK(DAY): + deparseAppendStringInfoString(state, " day"); + break; + case INTERVAL_MASK(HOUR): + deparseAppendStringInfoString(state, " hour"); + break; + case INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " minute"); + break; + case INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + deparseAppendStringInfoString(state, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + deparseAppendStringInfoString(state, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + deparseAppendStringInfoString(state, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + deparseAppendStringInfoString(state, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + deparseAppendStringInfo(state, "(%d)", precision); + } +} + +static void deparseNullTest(DeparseState *state, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(state, (Node *) null_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + switch (null_test->nulltesttype) + { + case IS_NULL: + deparseAppendStringInfoString(state, " IS NULL"); + break; + case IS_NOT_NULL: + deparseAppendStringInfoString(state, " IS NOT NULL"); + break; + } +} + +// "case_expr" in gram.y +static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(state, (Node *) case_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + parent_level = deparseStateIncreaseNestingLevel(state); + + foreach(lc, case_expr->args) + { + deparseCaseWhen(state, castNode(CaseWhen, lfirst(lc))); + } + + if (case_expr->defresult != NULL) + { + deparseAppendPartGroup(state, "ELSE", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_expr->defresult, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + deparseAppendStringInfoChar(state, ' '); + deparseStateDecreaseNestingLevel(state, parent_level); + + deparseAppendStringInfoString(state, "END"); +} + +// "when_clause" in gram.y +static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when) +{ + deparseAppendPartGroup(state, "WHEN", DEPARSE_PART_INDENT); + deparseExpr(state, (Node *) case_when->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " THEN "); + deparseExpr(state, (Node *) case_when->result, DEPARSE_NODE_CONTEXT_A_EXPR); +} + +static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)) || + IsA(a_indirection->arg, JsonFuncExpr); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, a_indirection->arg, need_parens ? DEPARSE_NODE_CONTEXT_A_EXPR : DEPARSE_NODE_CONTEXT_NONE); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + deparseOptIndirection(state, a_indirection->indirection, 0); +} + +static void deparseAIndices(DeparseState *state, A_Indices *a_indices) +{ + deparseAppendStringInfoChar(state, '['); + if (a_indices->lidx != NULL) + deparseExpr(state, a_indices->lidx, DEPARSE_NODE_CONTEXT_A_EXPR); + if (a_indices->is_slice) + deparseAppendStringInfoChar(state, ':'); + if (a_indices->uidx != NULL) + deparseExpr(state, a_indices->uidx, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ']'); +} + +static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr) +{ + deparseAppendStringInfoString(state, "COALESCE("); + deparseExprList(state, coalesce_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + deparseAppendStringInfoString(state, "GREATEST("); + break; + case IS_LEAST: + deparseAppendStringInfoString(state, "LEAST("); + break; + } + deparseExprList(state, min_max_expr->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test) +{ + bool need_parens = IsA(boolean_test->arg, BoolExpr); + + if (need_parens) + deparseAppendStringInfoChar(state, '('); + + deparseExpr(state, (Node *) boolean_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (need_parens) + deparseAppendStringInfoChar(state, ')'); + + switch (boolean_test->booltesttype) + { + case IS_TRUE: + deparseAppendStringInfoString(state, " IS TRUE"); + break; + case IS_NOT_TRUE: + deparseAppendStringInfoString(state, " IS NOT TRUE"); + break; + case IS_FALSE: + deparseAppendStringInfoString(state, " IS FALSE"); + break; + case IS_NOT_FALSE: + deparseAppendStringInfoString(state, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + deparseAppendStringInfoString(state, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + deparseAppendStringInfoString(state, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +// "columnDef" and "alter_table_cmd" in gram.y +static void deparseColumnDef(DeparseState *state, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(column_def->colname)); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(state, column_def->typeName); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->storage_name) + { + deparseAppendStringInfoString(state, "STORAGE "); + deparseAppendStringInfoString(state, column_def->storage_name); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->raw_default != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseExpr(state, column_def->raw_default, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->compression != NULL) + { + deparseAppendStringInfoString(state, "COMPRESSION "); + deparseAppendStringInfoString(state, column_def->compression); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(state, column_def->fdwoptions); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(state, castNode(Constraint, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(state, column_def->collClause); + } + + removeTrailingSpace(state); +} + +static void deparseInsertOverride(DeparseState *state, OverridingKind override) +{ + switch (override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + deparseAppendStringInfoString(state, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + deparseAppendStringInfoString(state, "OVERRIDING SYSTEM VALUE "); + break; + } +} + +static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(state, insert_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "INSERT INTO", DEPARSE_PART_INDENT); + deparseRangeVar(state, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, insert_stmt->cols); + deparseAppendStringInfoString(state, ") "); + } + + deparseInsertOverride(state, insert_stmt->override); + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(state, castNode(SelectStmt, insert_stmt->selectStmt), DEPARSE_NODE_CONTEXT_INSERT_SELECT); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(state, insert_stmt->onConflictClause); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, insert_stmt->returningList); + } + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseInferClause(DeparseState *state, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(state, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + + if (infer_clause->conname != NULL) + { + deparseAppendStringInfoString(state, "ON CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(infer_clause->conname)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, infer_clause->whereClause); + + removeTrailingSpace(state); +} + +static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "ON CONFLICT", DEPARSE_PART_INDENT); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(state, on_conflict_clause->infer); + deparseAppendStringInfoChar(state, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + deparseAppendStringInfoString(state, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + deparseAppendStringInfoString(state, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, on_conflict_clause->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, on_conflict_clause->whereClause); + + removeTrailingSpace(state); +} + +static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (update_stmt->withClause != NULL) + { + deparseWithClause(state, update_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "UPDATE", DEPARSE_PART_INDENT); + deparseRangeVar(state, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); + deparseSetClauseList(state, update_stmt->targetList); + deparseAppendStringInfoChar(state, ' '); + } + + deparseFromClause(state, update_stmt->fromClause); + deparseWhereOrCurrentClause(state, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, update_stmt->returningList); + } + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +// "MergeStmt" in gram.y +static void deparseMergeStmt(DeparseState *state, MergeStmt *merge_stmt) +{ + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (merge_stmt->withClause != NULL) + { + deparseWithClause(state, merge_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "MERGE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "INTO "); + deparseRangeVar(state, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseTableRef(state, merge_stmt->sourceRelation); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "ON "); + deparseExpr(state, merge_stmt->joinCondition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + ListCell *lc; + foreach (lc, merge_stmt->mergeWhenClauses) + { + MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); + + deparseAppendStringInfoString(state, "WHEN "); + + switch (clause->matchKind) + { + case MERGE_WHEN_MATCHED: + deparseAppendStringInfoString(state, "MATCHED "); + break; + case MERGE_WHEN_NOT_MATCHED_BY_SOURCE: + deparseAppendStringInfoString(state, "NOT MATCHED BY SOURCE "); + break; + case MERGE_WHEN_NOT_MATCHED_BY_TARGET: + deparseAppendStringInfoString(state, "NOT MATCHED "); + break; + } + + if (clause->condition) + { + deparseAppendStringInfoString(state, "AND "); + deparseExpr(state, clause->condition, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "THEN "); + + switch (clause->commandType) { + case CMD_INSERT: + deparseAppendStringInfoString(state, "INSERT "); + + if (clause->targetList) { + deparseAppendStringInfoChar(state, '('); + deparseInsertColumnList(state, clause->targetList); + deparseAppendStringInfoString(state, ") "); + } + + deparseInsertOverride(state, clause->override); + + if (clause->values) { + deparseAppendStringInfoString(state, "VALUES ("); + deparseExprList(state, clause->values); + deparseAppendStringInfoString(state, ")"); + } else { + deparseAppendStringInfoString(state, "DEFAULT VALUES "); + } + + break; + case CMD_UPDATE: + deparseAppendStringInfoString(state, "UPDATE SET "); + deparseSetClauseList(state, clause->targetList); + break; + case CMD_DELETE: + deparseAppendStringInfoString(state, "DELETE"); + break; + case CMD_NOTHING: + deparseAppendStringInfoString(state, "DO NOTHING"); + break; + default: + elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); + break; + } + + if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) + deparseAppendStringInfoChar(state, ' '); + } + + if (merge_stmt->returningList) + { + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, merge_stmt->returningList); + } + + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt) +{ + DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); + + if (delete_stmt->withClause != NULL) + { + deparseWithClause(state, delete_stmt->withClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "DELETE", DEPARSE_PART_INDENT); + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (delete_stmt->usingClause != NULL) + { + deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); + deparseFromList(state, delete_stmt->usingClause); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereOrCurrentClause(state, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); + deparseTargetList(state, delete_stmt->returningList); + } + + removeTrailingSpace(state); + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + deparseAppendPartGroup(state, "FOR KEY SHARE", DEPARSE_PART_INDENT); + break; + case LCS_FORSHARE: + deparseAppendPartGroup(state, "FOR SHARE", DEPARSE_PART_INDENT); + break; + case LCS_FORNOKEYUPDATE: + deparseAppendPartGroup(state, "FOR NO KEY UPDATE", DEPARSE_PART_INDENT); + break; + case LCS_FORUPDATE: + deparseAppendPartGroup(state, "FOR UPDATE", DEPARSE_PART_INDENT); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + deparseAppendStringInfoString(state, "OF "); + deparseQualifiedNameList(state, locking_clause->lockedRels); + deparseAppendStringInfoChar(state, ' '); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + deparseAppendStringInfoString(state, "NOWAIT"); + break; + case LockWaitSkip: + deparseAppendStringInfoString(state, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(state); +} + +static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default) +{ + deparseAppendStringInfoString(state, "DEFAULT"); +} + +static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + deparseAppendStringInfoString(state, "CREATE CAST ("); + deparseTypeName(state, create_cast_stmt->sourcetype); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, create_cast_stmt->targettype); + deparseAppendStringInfoString(state, ") "); + + if (create_cast_stmt->func != NULL) + { + deparseAppendStringInfoString(state, "WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_cast_stmt->func); + deparseAppendStringInfoChar(state, ' '); + } + else if (create_cast_stmt->inout) + { + deparseAppendStringInfoString(state, "WITH INOUT "); + } + else + { + deparseAppendStringInfoString(state, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + deparseAppendStringInfoString(state, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + deparseAppendStringInfoString(state, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(DeparseState *state, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE OPERATOR CLASS "); + + deparseAnyName(state, create_op_class_stmt->opclassname); + deparseAppendStringInfoChar(state, ' '); + + if (create_op_class_stmt->isDefault) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseAppendStringInfoString(state, "FOR TYPE "); + deparseTypeName(state, create_op_class_stmt->datatype); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_class_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + deparseAppendStringInfoString(state, "FAMILY "); + deparseAnyName(state, create_op_class_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "AS "); + deparseOpclassItemList(state, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(DeparseState *state, CreateOpFamilyStmt *create_op_family_stmt) +{ + deparseAppendStringInfoString(state, "CREATE OPERATOR FAMILY "); + + deparseAnyName(state, create_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(state, create_op_class_item->name); + else + deparseAnyOperator(state, create_op_class_item->name->objname); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + deparseAppendStringInfoString(state, "FOR ORDER BY "); + deparseAnyName(state, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoChar(state, ')'); + } + removeTrailingSpace(state); + break; + case OPCLASS_ITEM_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseAppendStringInfo(state, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, create_op_class_item->class_args); + deparseAppendStringInfoString(state, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(state, create_op_class_item->name); + removeTrailingSpace(state); + break; + case OPCLASS_ITEM_STORAGETYPE: + deparseAppendStringInfoString(state, "STORAGE "); + deparseTypeName(state, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(DeparseState *state, TableLikeClause *table_like_clause) +{ + deparseAppendStringInfoString(state, "LIKE "); + deparseRangeVar(state, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + deparseAppendStringInfoString(state, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + deparseAppendStringInfoString(state, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) + deparseAppendStringInfoString(state, "INCLUDING COMPRESSION "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + deparseAppendStringInfoString(state, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + deparseAppendStringInfoString(state, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + deparseAppendStringInfoString(state, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + deparseAppendStringInfoString(state, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + deparseAppendStringInfoString(state, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + deparseAppendStringInfoString(state, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + deparseAppendStringInfoString(state, "INCLUDING STORAGE "); + } + removeTrailingSpace(state); +} + +static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + deparseAppendStringInfoString(state, "CREATE DOMAIN "); + deparseAnyName(state, create_domain_stmt->domainname); + deparseAppendStringInfoString(state, " AS "); + + deparseTypeName(state, create_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(state, create_domain_stmt->collClause); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(state, castNode(Constraint, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseCreateExtensionStmt(DeparseState *state, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseColId(state, create_extension_stmt->extname); + deparseAppendStringInfoChar(state, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + deparseAppendStringInfoString(state, "VERSION "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + deparseAppendStringInfoString(state, "CASCADE"); + } + else + { + Assert(false); + } + + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +// "ColConstraintElem" and "ConstraintElem" in gram.y +static void deparseConstraint(DeparseState *state, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(constraint->conname)); + deparseAppendStringInfoChar(state, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + deparseAppendStringInfoString(state, "NULL "); + break; + case CONSTR_NOTNULL: + deparseAppendStringInfoString(state, "NOT NULL "); + break; + case CONSTR_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + deparseBExpr(state, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + deparseAppendStringInfoString(state, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + deparseAppendStringInfoString(state, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + deparseAppendStringInfoString(state, "BY DEFAULT "); + break; + default: + Assert(false); + } + deparseAppendStringInfoString(state, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(state, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + deparseAppendStringInfoString(state, "GENERATED ALWAYS AS ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") STORED "); + break; + case CONSTR_CHECK: + deparseAppendStringInfoString(state, "CHECK ("); + deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + break; + case CONSTR_PRIMARY: + deparseAppendStringInfoString(state, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + deparseAppendStringInfoString(state, "UNIQUE "); + if (constraint->nulls_not_distinct) + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); + break; + case CONSTR_EXCLUSION: + deparseAppendStringInfoString(state, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(constraint->access_method)); + deparseAppendStringInfoChar(state, ' '); + } + deparseAppendStringInfoChar(state, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(state, castNode(IndexElem, linitial(exclusion))); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyOperator(state, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + if (constraint->where_clause != NULL) + { + deparseAppendStringInfoString(state, "WHERE ("); + deparseExpr(state, constraint->where_clause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + deparseAppendStringInfoString(state, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + deparseAppendStringInfoString(state, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + deparseAppendStringInfoString(state, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + deparseAppendStringInfoString(state, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + bool valueOnly = false; + + if (list_length(constraint->keys) == 1) { + Node* firstKey = constraint->keys->elements[0].ptr_value; + valueOnly = IsA(firstKey, String) && !strcmp("value", ((String*)firstKey)->sval); + } + + if (!valueOnly) { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->keys); + deparseAppendStringInfoString(state, ") "); + } + } + + if (list_length(constraint->fk_attrs) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->fk_attrs); + deparseAppendStringInfoString(state, ") "); + } + + if (constraint->pktable != NULL) + { + deparseAppendStringInfoString(state, "REFERENCES "); + deparseRangeVar(state, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, constraint->pk_attrs); + deparseAppendStringInfoString(state, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + deparseAppendStringInfoString(state, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + deparseAppendStringInfoString(state, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + deparseAppendStringInfoString(state, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + deparseAppendStringInfoString(state, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + deparseAppendStringInfoString(state, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + deparseAppendStringInfoString(state, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + deparseAppendStringInfoString(state, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + case FKCONSTR_ACTION_SETDEFAULT: + deparseAppendStringInfoString(state, "ON DELETE SET "); + + switch (constraint->fk_del_action) { + case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: deparseAppendStringInfoString(state, "NULL "); break; + } + + if (constraint->fk_del_set_cols) { + deparseAppendStringInfoString(state, "("); + ListCell *lc; + foreach (lc, constraint->fk_del_set_cols) { + deparseAppendStringInfoString(state, strVal(lfirst(lc))); + if (lfirst(lc) != llast(constraint->fk_del_set_cols)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ")"); + } + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + deparseAppendStringInfoString(state, "INCLUDE ("); + deparseColumnList(state, constraint->including); + deparseAppendStringInfoString(state, ") "); + } + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + case CONSTR_UNIQUE: + case CONSTR_EXCLUSION: + deparseOptWith(state, constraint->options); + break; + default: + break; + } + + if (constraint->indexname != NULL) + deparseAppendStringInfo(state, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + deparseAppendStringInfo(state, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + deparseAppendStringInfoString(state, "DEFERRABLE "); + + if (constraint->initdeferred) + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + deparseAppendStringInfoString(state, "NO INHERIT "); + + if (constraint->skip_validation) + deparseAppendStringInfoString(state, "NOT VALID "); + + removeTrailingSpace(state); +} + +// "ReturnStmt" in gram.y +static void deparseReturnStmt(DeparseState *state, ReturnStmt *return_stmt) +{ + deparseAppendStringInfoString(state, "RETURN "); + deparseExpr(state, return_stmt->returnval, DEPARSE_NODE_CONTEXT_A_EXPR); +} + +static void deparseCreateFunctionStmt(DeparseState *state, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + deparseAppendStringInfoString(state, "CREATE "); + if (create_function_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + if (create_function_stmt->is_procedure) + deparseAppendStringInfoString(state, "PROCEDURE "); + else + deparseAppendStringInfoString(state, "FUNCTION "); + + deparseFuncName(state, create_function_stmt->funcname); + + deparseAppendStringInfoChar(state, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(state, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + deparseAppendStringInfoString(state, ", "); + } + else + { + tableFunc = true; + } + } + deparseAppendStringInfoString(state, ") "); + + if (tableFunc) + { + deparseAppendStringInfoString(state, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(state, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + deparseAppendStringInfoString(state, ", "); + } + } + deparseAppendStringInfoString(state, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + deparseAppendStringInfoString(state, "RETURNS "); + deparseTypeName(state, create_function_stmt->returnType); + deparseAppendStringInfoChar(state, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + { + deparseReturnStmt(state, castNode(ReturnStmt, create_function_stmt->sql_body)); + } + else + { + deparseAppendStringInfoString(state, "BEGIN ATOMIC "); + if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) + { + List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); + foreach(lc, body_stmt_list) + { + if (IsA(lfirst(lc), ReturnStmt)) + { + deparseReturnStmt(state, lfirst_node(ReturnStmt, lc)); + deparseAppendStringInfoString(state, "; "); + } + else + { + deparseStmt(state, lfirst(lc)); + deparseAppendStringInfoString(state, "; "); + } + } + } + + deparseAppendStringInfoString(state, "END "); + } + } + + removeTrailingSpace(state); +} + +// "func_arg", "func_arg_with_default" and other places in gram.y +static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + deparseAppendStringInfoString(state, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + deparseAppendStringInfoString(state, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + deparseAppendStringInfoString(state, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + deparseAppendStringInfoString(state, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + deparseAppendStringInfoString(state, function_parameter->name); + deparseAppendStringInfoChar(state, ' '); + } + + deparseTypeName(state, function_parameter->argType); + deparseAppendStringInfoChar(state, ' '); + + if (function_parameter->defexpr != NULL) + { + deparseAppendStringInfoString(state, "= "); + deparseExpr(state, function_parameter->defexpr, DEPARSE_NODE_CONTEXT_A_EXPR); + } + + removeTrailingSpace(state); +} + +static void deparseCheckPointStmt(DeparseState *state, CheckPointStmt *check_point_stmt) +{ + deparseAppendStringInfoString(state, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(DeparseState *state, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + deparseAppendStringInfoString(state, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(state, create_schema_stmt->schemaname); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + deparseAppendStringInfoString(state, "AUTHORIZATION "); + deparseRoleSpec(state, create_schema_stmt->authrole); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(state, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseAlterRoleSetStmt(DeparseState *state, AlterRoleSetStmt *alter_role_set_stmt) +{ + deparseAppendStringInfoString(state, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + deparseAppendStringInfoString(state, "ALL"); + else + deparseRoleSpec(state, alter_role_set_stmt->role); + + deparseAppendStringInfoChar(state, ' '); + + if (alter_role_set_stmt->database != NULL) + { + deparseAppendStringInfoString(state, "IN DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(alter_role_set_stmt->database)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseVariableSetStmt(state, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(DeparseState *state, CreateConversionStmt *create_conversion_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + if (create_conversion_stmt->def) + deparseAppendStringInfoString(state, "DEFAULT "); + + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, create_conversion_stmt->conversion_name); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "FOR "); + deparseStringLiteral(state, create_conversion_stmt->for_encoding_name); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, create_conversion_stmt->to_encoding_name); + + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + deparseAppendStringInfoString(state, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + deparseAppendStringInfoString(state, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + deparseAppendStringInfoString(state, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + deparseAppendStringInfoString(state, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + deparseAppendStringInfoString(state, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(DeparseState *state, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(state, partition_elem->name); + deparseAppendStringInfoChar(state, ' '); + } + else if (partition_elem->expr != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, partition_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + deparseOptCollate(state, partition_elem->collation); + deparseAnyName(state, partition_elem->opclass); + + removeTrailingSpace(state); +} + +static void deparsePartitionSpec(DeparseState *state, PartitionSpec *partition_spec) +{ + ListCell *lc; + + deparseAppendPartGroup(state, "PARTITION BY", DEPARSE_PART_INDENT); + + switch (partition_spec->strategy) + { + case PARTITION_STRATEGY_LIST: + deparseAppendStringInfoString(state, "LIST"); + break; + case PARTITION_STRATEGY_HASH: + deparseAppendStringInfoString(state, "HASH"); + break; + case PARTITION_STRATEGY_RANGE: + deparseAppendStringInfoString(state, "RANGE"); + break; + } + + deparseAppendStringInfoString(state, " ("); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(state, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +static void deparsePartitionBoundSpec(DeparseState *state, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + deparseAppendStringInfoString(state, "DEFAULT"); + return; + } + + deparseAppendStringInfoString(state, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + deparseAppendStringInfo(state, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + deparseAppendStringInfoString(state, "IN ("); + deparseExprList(state, partition_bound_spec->listdatums); + deparseAppendStringInfoChar(state, ')'); + break; + case PARTITION_STRATEGY_RANGE: + deparseAppendStringInfoString(state, "FROM ("); + deparseExprList(state, partition_bound_spec->lowerdatums); + deparseAppendStringInfoString(state, ") TO ("); + deparseExprList(state, partition_bound_spec->upperdatums); + deparseAppendStringInfoChar(state, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(DeparseState *state, PartitionCmd *partition_cmd) +{ + deparseRangeVar(state, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + deparseAppendStringInfoChar(state, ' '); + deparsePartitionBoundSpec(state, partition_cmd->bound); + } + if (partition_cmd->concurrent) + deparseAppendStringInfoString(state, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(state, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(state, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(state, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(DeparseState *state, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (is_foreign_table) + deparseAppendStringInfoString(state, "FOREIGN "); + + deparseOptTemp(state, create_stmt->relation->relpersistence); + + deparseAppendStringInfoString(state, "TABLE "); + + if (create_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseRangeVar(state, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_stmt->ofTypename != NULL) + { + deparseAppendStringInfoString(state, "OF "); + deparseTypeName(state, create_stmt->ofTypename); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + deparseAppendStringInfoString(state, "PARTITION OF "); + deparseRangeVar(state, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + DeparseStateNestingLevel *parent_level = NULL; + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + deparseAppendStringInfoChar(state, '('); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(state, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoString(state, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + deparseAppendStringInfoString(state, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(state, create_stmt->partbound); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseOptInherit(state, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(state, create_stmt->partspec); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(state, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + deparseAppendStringInfoString(state, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(state); +} + +static void deparseCreateFdwStmt(DeparseState *state, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(state, create_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); + } + + deparseCreateGenericOptions(state, create_fdw_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterFdwStmt(DeparseState *state, AlterFdwStmt *alter_fdw_stmt) +{ + deparseAppendStringInfoString(state, "ALTER FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(alter_fdw_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(state, alter_fdw_stmt->func_options); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(state, alter_fdw_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateForeignServerStmt(DeparseState *state, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + deparseAppendStringInfoString(state, "TYPE "); + deparseStringLiteral(state, create_foreign_server_stmt->servertype); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + deparseAppendStringInfoString(state, "VERSION "); + deparseStringLiteral(state, create_foreign_server_stmt->version); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->fdwname)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, create_foreign_server_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterForeignServerStmt(DeparseState *state, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + deparseAppendStringInfoString(state, "ALTER SERVER "); + + deparseAppendStringInfoString(state, quote_identifier(alter_foreign_server_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (alter_foreign_server_stmt->has_version) + { + deparseAppendStringInfoString(state, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(state, alter_foreign_server_stmt->version); + else + deparseAppendStringInfoString(state, "NULL"); + deparseAppendStringInfoChar(state, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(state, alter_foreign_server_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateUserMappingStmt(DeparseState *state, CreateUserMappingStmt *create_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, create_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, create_user_mapping_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreatedbStmt(DeparseState *state, CreatedbStmt *createdb_stmt) +{ + deparseAppendStringInfoString(state, "CREATE DATABASE "); + deparseColId(state, createdb_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, createdb_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterUserMappingStmt(DeparseState *state, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "ALTER USER MAPPING FOR "); + deparseRoleSpec(state, alter_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(alter_user_mapping_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + deparseAlterGenericOptions(state, alter_user_mapping_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseDropUserMappingStmt(DeparseState *state, DropUserMappingStmt *drop_user_mapping_stmt) +{ + deparseAppendStringInfoString(state, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, "FOR "); + deparseRoleSpec(state, drop_user_mapping_stmt->user); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "SERVER "); + deparseAppendStringInfoString(state, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(DeparseState *state, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + deparseAppendStringInfoString(state, "FOR "); + deparseAppendStringInfoString(state, quote_identifier(sec_label_stmt->provider)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + deparseAppendStringInfoString(state, "COLUMN "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseAnyName(state, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseValue(state, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(state, sec_label_stmt->label); + else + deparseAppendStringInfoString(state, "NULL"); +} + +static void deparseCreateForeignTableStmt(DeparseState *state, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(state, &create_foreign_table_stmt->base, true); + + deparseAppendStringInfoString(state, " SERVER "); + deparseAppendStringInfoString(state, quote_identifier(create_foreign_table_stmt->servername)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(state, create_foreign_table_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseImportForeignSchemaStmt(DeparseState *state, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + deparseAppendStringInfoString(state, "IMPORT FOREIGN SCHEMA "); + + deparseAppendStringInfoString(state, import_foreign_schema_stmt->remote_schema); + deparseAppendStringInfoChar(state, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + deparseAppendStringInfoString(state, "LIMIT TO ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + deparseAppendStringInfoString(state, "EXCEPT ("); + deparseRelationExprList(state, import_foreign_schema_stmt->table_list); + deparseAppendStringInfoString(state, ") "); + break; + } + + deparseAppendStringInfoString(state, "FROM SERVER "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->server_name)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "INTO "); + deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->local_schema)); + deparseAppendStringInfoChar(state, ' '); + + deparseCreateGenericOptions(state, import_foreign_schema_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateTableAsStmt(DeparseState *state, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + deparseAppendStringInfoString(state, "CREATE "); + + deparseOptTemp(state, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseIntoClause(state, create_table_as_stmt->into); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(state, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(state, castNode(SelectStmt, create_table_as_stmt->query), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_table_as_stmt->into->skipData) + deparseAppendStringInfoString(state, "WITH NO DATA "); + + removeTrailingSpace(state); +} + +static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (view_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseOptTemp(state, view_stmt->view->relpersistence); + + deparseAppendStringInfoString(state, "VIEW "); + deparseRangeVar(state, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, view_stmt->aliases); + deparseAppendStringInfoString(state, ") "); + } + + deparseOptWith(state, view_stmt->options); + + deparseAppendStringInfoString(state, "AS "); + deparseSelectStmt(state, castNode(SelectStmt, view_stmt->query), DEPARSE_NODE_CONTEXT_NONE); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + deparseAppendStringInfoString(state, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + deparseAppendStringInfoString(state, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(state); +} + +static void deparseDropStmt(DeparseState *state, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + deparseAppendStringInfoString(state, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(state, strVal(llast(l))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(state, drop_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(state, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(state, drop_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + deparseAppendStringInfoString(state, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + deparseAppendStringInfoString(state, "ROLLUP ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + case GROUPING_SET_CUBE: + deparseAppendStringInfoString(state, "CUBE ("); + deparseExprList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + case GROUPING_SET_SETS: + deparseAppendStringInfoString(state, "GROUPING SETS ("); + deparseGroupByList(state, grouping_set->content); + deparseAppendStringInfoChar(state, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(DeparseState *state, DropTableSpaceStmt *drop_table_space_stmt) +{ + deparseAppendStringInfoString(state, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(DeparseState *state, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + deparseColId(state, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + + if (alter_object_depends_stmt->remove) + deparseAppendStringInfoString(state, "NO "); + + deparseAppendStringInfo(state, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); +} + +static void deparseAlterObjectSchemaStmt(DeparseState *state, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + deparseAppendStringInfoString(state, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " SET SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(alter_object_schema_stmt->newschema)); +} + +// "alter_table_cmd" in gram.y +static void deparseAlterTableCmd(DeparseState *state, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ADD ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "ADD COLUMN "); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "DROP ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "DROP "); + break; + case AT_AddIndex: /* add index */ + deparseAppendStringInfoString(state, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + deparseAppendStringInfoString(state, "ADD "); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + deparseAppendStringInfoString(state, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + deparseAppendStringInfoString(state, "ALTER ATTRIBUTE "); + else + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + deparseAppendStringInfoString(state, "OWNER TO "); + deparseRoleSpec(state, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + deparseAppendStringInfoString(state, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + deparseAppendStringInfoString(state, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + deparseAppendStringInfoString(state, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + deparseAppendStringInfoString(state, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + deparseAppendStringInfoString(state, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + deparseAppendStringInfoString(state, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + deparseAppendStringInfoString(state, "SET "); + break; + case AT_SetAccessMethod: + deparseAppendStringInfo(state, "SET ACCESS METHOD "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + deparseAppendStringInfoString(state, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + deparseAppendStringInfoString(state, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER ALL "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + deparseAppendStringInfoString(state, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + deparseAppendStringInfoString(state, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + deparseAppendStringInfoString(state, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + deparseAppendStringInfoString(state, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + deparseAppendStringInfoString(state, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + deparseAppendStringInfoString(state, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + deparseAppendStringInfoString(state, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + deparseAppendStringInfoString(state, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + deparseAppendStringInfoString(state, "OF "); + break; + case AT_DropOf: /* NOT OF */ + deparseAppendStringInfoString(state, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + deparseAppendStringInfoString(state, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + deparseAppendStringInfoString(state, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + deparseAppendStringInfoString(state, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + deparseAppendStringInfoString(state, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + deparseAppendStringInfoString(state, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + deparseAppendStringInfoString(state, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + deparseAppendStringInfoString(state, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + deparseAppendStringInfoString(state, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + deparseAppendStringInfoString(state, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + deparseAppendStringInfoString(state, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + deparseAppendStringInfoString(state, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + case AT_SetExpression: + deparseAppendStringInfoString(state, "ALTER COLUMN "); + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + else + deparseAppendStringInfoString(state, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(alter_table_cmd->name)); + deparseAppendStringInfoChar(state, ' '); + } else if (alter_table_cmd->subtype == AT_SetAccessMethod) + { + deparseAppendStringInfoString(state, " DEFAULT"); + } + + if (alter_table_cmd->num > 0) + deparseAppendStringInfo(state, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + deparseAppendStringInfoString(state, options); + deparseAppendStringInfoChar(state, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); + deparseAppendStringInfoString(state, "FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(state, castNode(ColumnDef, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + } + break; + case AT_SetStatistics: + if (alter_table_cmd->def != NULL) + deparseSignedIconst(state, alter_table_cmd->def); + else + deparseAppendStringInfoString(state, "DEFAULT"); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetStorage: + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + deparseAppendStringInfoString(state, "DEFAULT"); + else + deparseColId(state, strVal(alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(state, castNode(Constraint, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(state, castNode(List, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(state, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_AddOf: + deparseTypeName(state, castNode(TypeName, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(state, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + deparseAppendStringInfoChar(state, ' '); + break; + case AT_SetExpression: + deparseAppendStringInfoString(state, "SET EXPRESSION AS ("); + deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(state, alter_table_cmd->behavior); + + removeTrailingSpace(state); +} + +static DeparseNodeContext deparseAlterTableObjType(DeparseState *state, ObjectType type) +{ + switch (type) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + return DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + return DEPARSE_NODE_CONTEXT_NONE; +} + +static void deparseAlterTableMoveAllStmt(DeparseState *state, AlterTableMoveAllStmt *move_all_stmt) +{ + deparseAppendStringInfoString(state, "ALTER "); + deparseAlterTableObjType(state, move_all_stmt->objtype); + + deparseAppendStringInfoString(state, "ALL IN TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->orig_tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (move_all_stmt->roles) + { + deparseAppendStringInfoString(state, "OWNED BY "); + deparseRoleList(state, move_all_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "SET TABLESPACE "); + deparseAppendStringInfoString(state, move_all_stmt->new_tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (move_all_stmt->nowait) + { + deparseAppendStringInfoString(state, "NOWAIT"); + } +} + +static void deparseAlterTableStmt(DeparseState *state, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(state, alter_table_stmt->objtype); + + if (alter_table_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRangeVar(state, alter_table_stmt->relation, context); + deparseAppendStringInfoChar(state, ' '); + + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(state, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); +} + +static void deparseAlterTableSpaceOptionsStmt(DeparseState *state, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TABLESPACE "); + deparseColId(state, alter_table_space_options_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (alter_table_space_options_stmt->isReset) + deparseAppendStringInfoString(state, "RESET "); + else + deparseAppendStringInfoString(state, "SET "); + + deparseRelOptions(state, alter_table_space_options_stmt->options); +} + +// "AlterDomainStmt" in gram.y +static void deparseAlterDomainStmt(DeparseState *state, AlterDomainStmt *alter_domain_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DOMAIN "); + deparseAnyName(state, alter_domain_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + deparseAppendStringInfoString(state, "SET DEFAULT "); + deparseExpr(state, alter_domain_stmt->def, DEPARSE_NODE_CONTEXT_A_EXPR); + } + else + { + deparseAppendStringInfoString(state, "DROP DEFAULT"); + } + break; + case 'N': + deparseAppendStringInfoString(state, "DROP NOT NULL"); + break; + case 'O': + deparseAppendStringInfoString(state, "SET NOT NULL"); + break; + case 'C': + deparseAppendStringInfoString(state, "ADD "); + deparseConstraint(state, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + deparseAppendStringInfoString(state, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + deparseAppendStringInfoString(state, " CASCADE"); + break; + case 'V': + deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(DeparseState *state, RenameStmt *rename_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + deparseAppendStringInfoString(state, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(state, strVal(rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME COLUMN "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, quote_identifier(strVal(rename_stmt->object))); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(state, castNode(List, rename_stmt->object)); + deparseAppendStringInfoString(state, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + deparseAppendStringInfoString(state, " RENAME ATTRIBUTE "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + break; + default: + Assert(false); + break; + } + + deparseAppendStringInfoString(state, "TO "); + deparseAppendStringInfoString(state, quote_identifier(rename_stmt->newname)); + deparseAppendStringInfoChar(state, ' '); + + deparseOptDropBehavior(state, rename_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseTransactionStmt(DeparseState *state, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + deparseAppendStringInfoString(state, "BEGIN "); + deparseTransactionModeList(state, transaction_stmt->options); + break; + case TRANS_STMT_START: + deparseAppendStringInfoString(state, "START TRANSACTION "); + deparseTransactionModeList(state, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + deparseAppendStringInfoString(state, "COMMIT "); + if (transaction_stmt->chain) + deparseAppendStringInfoString(state, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + deparseAppendStringInfoString(state, "ROLLBACK "); + if (transaction_stmt->chain) + deparseAppendStringInfoString(state, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + deparseAppendStringInfoString(state, "SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + deparseAppendStringInfoString(state, "RELEASE "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + deparseAppendStringInfoString(state, "ROLLBACK "); + deparseAppendStringInfoString(state, "TO SAVEPOINT "); + deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + deparseAppendStringInfoString(state, "PREPARE TRANSACTION "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + deparseAppendStringInfoString(state, "COMMIT PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + deparseAppendStringInfoString(state, "ROLLBACK PREPARED "); + deparseStringLiteral(state, transaction_stmt->gid); + break; + } + + removeTrailingSpace(state); +} + +// Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not +// supported for other SET statements +static bool isSetTimeZoneInterval(VariableSetStmt* stmt) +{ + if (!(strcmp(stmt->name, "timezone") == 0 && + list_length(stmt->args) == 1 && + IsA(linitial(stmt->args), TypeCast))) + return false; + + TypeName* typeName = castNode(TypeCast, linitial(stmt->args))->typeName; + + return (list_length(typeName->names) == 2 && + strcmp(strVal(linitial(typeName->names)), "pg_catalog") == 0 && + strcmp(strVal(llast(typeName->names)), "interval") == 0); +} + +static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + if (isSetTimeZoneInterval(variable_set_stmt)) + { + deparseAppendStringInfoString(state, "TIME ZONE "); + deparseVarList(state, variable_set_stmt->args); + } + else + { + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO "); + deparseVarList(state, variable_set_stmt->args); + } + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + deparseVarName(state, variable_set_stmt->name); + deparseAppendStringInfoString(state, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + deparseAppendStringInfoString(state, "SET "); + if (variable_set_stmt->is_local) + deparseAppendStringInfoString(state, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + deparseAppendStringInfoString(state, "TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + deparseAppendStringInfoString(state, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(state, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + deparseAppendStringInfoString(state, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(state, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + deparseAppendStringInfoString(state, "RESET "); + deparseVarName(state, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + deparseAppendStringInfoString(state, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(DeparseState *state, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, quote_identifier(dropdb_stmt->dbname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + deparseAppendStringInfoString(state, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseVacuumStmt(DeparseState *state, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + deparseAppendStringInfoString(state, "VACUUM "); + else + deparseAppendStringInfoString(state, "ANALYZE "); + + deparseUtilityOptionList(state, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(state, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + foreach(lc2, rel->va_cols) + { + deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + deparseAppendStringInfoString(state, ", "); + } + + removeTrailingSpace(state); +} + +static void deparseLoadStmt(DeparseState *state, LoadStmt *load_stmt) +{ + deparseAppendStringInfoString(state, "LOAD "); + deparseStringLiteral(state, load_stmt->filename); +} + +static void deparseLockStmt(DeparseState *state, LockStmt *lock_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "LOCK TABLE "); + + deparseRelationExprList(state, lock_stmt->relations); + deparseAppendStringInfoChar(state, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + deparseAppendStringInfoString(state, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + deparseAppendStringInfoString(state, "ACCESS SHARE "); + break; + case RowShareLock: + deparseAppendStringInfoString(state, "ROW SHARE "); + break; + case RowExclusiveLock: + deparseAppendStringInfoString(state, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + deparseAppendStringInfoString(state, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + deparseAppendStringInfoString(state, "SHARE "); + break; + case ShareRowExclusiveLock: + deparseAppendStringInfoString(state, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + deparseAppendStringInfoString(state, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + deparseAppendStringInfoString(state, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + deparseAppendStringInfoString(state, "MODE "); + } + + if (lock_stmt->nowait) + deparseAppendStringInfoString(state, "NOWAIT "); + + removeTrailingSpace(state); +} + +static void deparseConstraintsSetStmt(DeparseState *state, ConstraintsSetStmt *constraints_set_stmt) +{ + deparseAppendStringInfoString(state, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(state, constraints_set_stmt->constraints); + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "ALL "); + } + + if (constraints_set_stmt->deferred) + deparseAppendStringInfoString(state, "DEFERRED"); + else + deparseAppendStringInfoString(state, "IMMEDIATE"); +} + +static void deparseExplainStmt(DeparseState *state, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + deparseAppendPartGroup(state, "EXPLAIN", DEPARSE_PART_NO_INDENT); + + deparseUtilityOptionList(state, explain_stmt->options); + + deparseExplainableStmt(state, explain_stmt->query); +} + +static void deparseCopyStmt(DeparseState *state, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + deparseAppendPartGroup(state, "COPY", DEPARSE_PART_INDENT); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(state, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, copy_stmt->attlist); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoChar(state, ' '); + } + + if (copy_stmt->query != NULL) + { + deparseAppendStringInfoChar(state, '('); + deparsePreparableStmt(state, copy_stmt->query); + deparseAppendStringInfoString(state, ") "); + } + + if (copy_stmt->is_from) + deparseAppendStringInfoString(state, "FROM "); + else + deparseAppendStringInfoString(state, "TO "); + + if (copy_stmt->is_program) + deparseAppendStringInfoString(state, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(state, copy_stmt->filename); + deparseAppendStringInfoChar(state, ' '); + } + else + { + if (copy_stmt->is_from) + deparseAppendStringInfoString(state, "STDIN "); + else + deparseAppendStringInfoString(state, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + // In some cases, equivalent expressions may have slightly different parse trees for `COPY` + // statements. For example the following two statements result in different (but equivalent) parse + // trees: + // + // - COPY foo FROM STDIN CSV FREEZE + // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) + // + // In order to make sure we deparse to the "correct" version, we always try to deparse to the older + // compact syntax first. + // + // The old syntax can be seen here in the Postgres 8.4 Reference: + // https://www.postgresql.org/docs/8.4/sql-copy.html + + bool old_fmt = true; + + // Loop over the options to see if any require the new `WITH (...)` syntax. + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + {} + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + {} + else + { + old_fmt = false; + break; + } + } + + // Branch to differing output modes, depending on if we can use the old syntax. + if (old_fmt) { + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + { + deparseAppendStringInfoString(state, "FREEZE "); + } + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + deparseAppendStringInfoString(state, "HEADER "); + } + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + { + deparseAppendStringInfoString(state, "CSV "); + } + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + { + deparseAppendStringInfoString(state, "FORCE QUOTE "); + deparseColumnList(state, castNode(List, def_elem->arg)); + } + else + { + // This isn't reachable, the conditions here are exactly the same as the first loop above. + Assert(false); + } + } + } else { + deparseAppendStringInfoString(state, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + deparseAppendStringInfoString(state, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + deparseAppendStringInfoString(state, "BINARY"); + else if (strcmp(format, "csv") == 0) + deparseAppendStringInfoString(state, "CSV"); + else if (strcmp(format, "text") == 0) + deparseAppendStringInfoString(state, "TEXT"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0) + { + deparseAppendStringInfoString(state, "FREEZE"); + deparseOptBoolean(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + deparseAppendStringInfoString(state, "DELIMITER "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + deparseAppendStringInfoString(state, "NULL "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0) + { + deparseAppendStringInfoString(state, "HEADER"); + deparseOptBoolean(state, def_elem->arg); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + deparseAppendStringInfoString(state, "QUOTE "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + deparseAppendStringInfoString(state, "ESCAPE "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + deparseAppendStringInfoString(state, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + deparseAppendStringInfoChar(state, '*'); + } + else if (IsA(def_elem->arg, List)) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + deparseAppendStringInfoString(state, "FORCE_NOT_NULL "); + + if (IsA(def_elem->arg, A_Star)) + deparseAStar(state, castNode(A_Star, def_elem->arg)); + else + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + deparseAppendStringInfoString(state, "FORCE_NULL "); + + if (IsA(def_elem->arg, A_Star)) + deparseAStar(state, castNode(A_Star, def_elem->arg)); + else + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, castNode(List, def_elem->arg)); + deparseAppendStringInfoChar(state, ')'); + } + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + deparseAppendStringInfoString(state, "ENCODING "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else + { + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + deparseAppendStringInfoChar(state, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(state, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(state, (union ValUnion *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(state, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoChar(state, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(state, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + } + + deparseWhereClause(state, copy_stmt->whereClause); + + removeTrailingSpace(state); +} + +static void deparseDoStmt(DeparseState *state, DoStmt *do_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(defel->arg))); + deparseAppendStringInfoChar(state, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoString(state, strval); + deparseAppendStringInfoString(state, delim); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseDiscardStmt(DeparseState *state, DiscardStmt *discard_stmt) +{ + deparseAppendStringInfoString(state, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + deparseAppendStringInfoString(state, "ALL"); + break; + case DISCARD_PLANS: + deparseAppendStringInfoString(state, "PLANS"); + break; + case DISCARD_SEQUENCES: + deparseAppendStringInfoString(state, "SEQUENCES"); + break; + case DISCARD_TEMP: + deparseAppendStringInfoString(state, "TEMP"); + break; + } +} + +static void deparseDefineStmt(DeparseState *state, DefineStmt *define_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (define_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(state, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(state, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(state, define_stmt->defnames); + break; + default: + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(state, define_stmt->args); + deparseAppendStringInfoChar(state, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + deparseAppendStringInfoString(state, "FROM "); + deparseAnyName(state, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(state, define_stmt->definition); + } + + removeTrailingSpace(state); +} + +static void deparseCompositeTypeStmt(DeparseState *state, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseRangeVar(state, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + deparseAppendStringInfoString(state, " AS ("); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateEnumStmt(DeparseState *state, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + DeparseStateNestingLevel *parent_level = NULL; + + deparseAppendStringInfoString(state, "CREATE TYPE "); + + deparseAnyName(state, create_enum_stmt->typeName); + deparseAppendStringInfoString(state, " AS ENUM ("); + parent_level = deparseStateIncreaseNestingLevel(state); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(state, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + deparseAppendCommaAndPart(state); + } + deparseStateDecreaseNestingLevel(state, parent_level); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateRangeStmt(DeparseState *state, CreateRangeStmt *create_range_stmt) +{ + deparseAppendStringInfoString(state, "CREATE TYPE "); + deparseAnyName(state, create_range_stmt->typeName); + deparseAppendStringInfoString(state, " AS RANGE "); + deparseDefinition(state, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(DeparseState *state, AlterEnumStmt *alter_enum_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_enum_stmt->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + deparseAppendStringInfoString(state, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseStringLiteral(state, alter_enum_stmt->newVal); + deparseAppendStringInfoChar(state, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + deparseAppendStringInfoString(state, "AFTER "); + else + deparseAppendStringInfoString(state, "BEFORE "); + deparseStringLiteral(state, alter_enum_stmt->newValNeighbor); + } + } + else + { + deparseAppendStringInfoString(state, "RENAME VALUE "); + deparseStringLiteral(state, alter_enum_stmt->oldVal); + deparseAppendStringInfoString(state, " TO "); + deparseStringLiteral(state, alter_enum_stmt->newVal); + } + + removeTrailingSpace(state); +} + +static void deparseAlterExtensionStmt(DeparseState *state, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_stmt->extname); + deparseAppendStringInfoString(state, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + deparseAppendStringInfoString(state, "TO "); + deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + deparseAppendStringInfoChar(state, ' '); + } + removeTrailingSpace(state); +} + +static void deparseAlterExtensionContentsStmt(DeparseState *state, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER EXTENSION "); + deparseColId(state, alter_extension_contents_stmt->extname); + deparseAppendStringInfoChar(state, ' '); + + if (alter_extension_contents_stmt->action == 1) + deparseAppendStringInfoString(state, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + deparseAppendStringInfoString(state, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(state, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(state, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(state, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseColId(state, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(DeparseState *state, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + deparseAppendStringInfoString(state, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + deparseAppendStringInfoString(state, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + deparseAppendStringInfoString(state, "create"); + else + deparseAppendStringInfoString(state, quote_identifier(access_priv->priv_name)); + } + else + { + deparseAppendStringInfoString(state, "ALL"); + } + deparseAppendStringInfoChar(state, ' '); + + if (list_length(access_priv->cols) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, access_priv->cols); + deparseAppendStringInfoChar(state, ')'); + } + + removeTrailingSpace(state); +} + +static void deparseGrantStmt(DeparseState *state, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + deparseAppendStringInfoString(state, "GRANT "); + else + deparseAppendStringInfoString(state, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + deparseAppendStringInfoString(state, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + } + else + { + deparseAppendStringInfoString(state, "ALL "); + } + + deparseAppendStringInfoString(state, "ON "); + + deparsePrivilegeTarget(state, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + deparseAppendStringInfoChar(state, ' '); + + if (grant_stmt->is_grant) + deparseAppendStringInfoString(state, "TO "); + else + deparseAppendStringInfoString(state, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(state, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + deparseAppendStringInfoString(state, "WITH GRANT OPTION "); + + deparseOptDropBehavior(state, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(state); +} + +static void deparseGrantRoleStmt(DeparseState *state, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + deparseAppendStringInfoString(state, "GRANT "); + else + deparseAppendStringInfoString(state, "REVOKE "); + + if (!grant_role_stmt->is_grant && list_length(grant_role_stmt->opt)) { + DefElem *defelem = castNode(DefElem, linitial(grant_role_stmt->opt)); + Assert(!castNode(Boolean, defelem->arg)->boolval); + + if (strcmp("admin", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "ADMIN "); + } else if (strcmp("inherit", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "INHERIT "); + } else if (strcmp("set", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "SET "); + } + + deparseAppendStringInfoString(state, "OPTION FOR "); + } + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + deparseAppendStringInfoChar(state, ','); + deparseAppendStringInfoChar(state, ' '); + } + + if (grant_role_stmt->is_grant) + deparseAppendStringInfoString(state, "TO "); + else + deparseAppendStringInfoString(state, "FROM "); + + deparseRoleList(state, grant_role_stmt->grantee_roles); + deparseAppendStringInfoChar(state, ' '); + + if (grant_role_stmt->is_grant) { + if (list_length(grant_role_stmt->opt) > 0) { + deparseAppendStringInfoString(state, "WITH "); + } + + foreach(lc, grant_role_stmt->opt) { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp("admin", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "ADMIN "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("inherit", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "INHERIT "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } else if (strcmp("set", defelem->defname) == 0) { + deparseAppendStringInfoString(state, "SET "); + deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); + } + + if (lnext(grant_role_stmt->opt, lc)) { + deparseAppendStringInfoChar(state, ','); + } + + deparseAppendStringInfoChar(state, ' '); + } + } + + if (grant_role_stmt->grantor) + { + deparseAppendStringInfoString(state, "GRANTED BY "); + deparseRoleSpec(state, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + if (grant_role_stmt->behavior == DROP_CASCADE) { + deparseAppendStringInfoString(state, "CASCADE "); + } + + removeTrailingSpace(state); +} + +static void deparseDropRoleStmt(DeparseState *state, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRoleList(state, drop_role_stmt->roles); +} + +static void deparseIndexStmt(DeparseState *state, IndexStmt *index_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (index_stmt->unique) + deparseAppendStringInfoString(state, "UNIQUE "); + + deparseAppendStringInfoString(state, "INDEX "); + + if (index_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(index_stmt->idxname)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendPartGroup(state, "ON", DEPARSE_PART_INDENT); + deparseRangeVar(state, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (index_stmt->accessMethod != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->accessMethod)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoChar(state, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + deparseAppendStringInfoString(state, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoString(state, ") "); + } + + if (index_stmt->nulls_not_distinct) + { + deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); + } + + deparseOptWith(state, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseAppendStringInfoString(state, quote_identifier(index_stmt->tableSpace)); + deparseAppendStringInfoChar(state, ' '); + } + + deparseWhereClause(state, index_stmt->whereClause); + + removeTrailingSpace(state); +} + +static void deparseAlterOpFamilyStmt(DeparseState *state, AlterOpFamilyStmt *alter_op_family_stmt) +{ + deparseAppendStringInfoString(state, "ALTER OPERATOR FAMILY "); + deparseAnyName(state, alter_op_family_stmt->opfamilyname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(alter_op_family_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + if (alter_op_family_stmt->isDrop) + deparseAppendStringInfoString(state, "DROP "); + else + deparseAppendStringInfoString(state, "ADD "); + + deparseOpclassItemList(state, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(DeparseState *state, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "PREPARE "); + deparseColId(state, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseTypeList(state, prepare_stmt->argtypes); + deparseAppendStringInfoChar(state, ')'); + } + deparseAppendStringInfoString(state, " AS "); + deparsePreparableStmt(state, prepare_stmt->query); +} + +static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "EXECUTE "); + deparseAppendStringInfoString(state, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, execute_stmt->params); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseDeallocateStmt(DeparseState *state, DeallocateStmt *deallocate_stmt) +{ + deparseAppendStringInfoString(state, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + deparseAppendStringInfoString(state, quote_identifier(deallocate_stmt->name)); + else + deparseAppendStringInfoString(state, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + deparseAppendStringInfoString(state, "PASSWORD "); + if (def_elem->arg == NULL) + { + deparseAppendStringInfoString(state, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(state, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + deparseAppendStringInfo(state, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + deparseAppendStringInfoString(state, "VALID UNTIL "); + deparseStringLiteral(state, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) + { + deparseAppendStringInfoString(state, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(DeparseState *state, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + deparseAppendStringInfo(state, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + deparseAppendStringInfoString(state, "ADMIN "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + deparseAppendStringInfoString(state, "IN ROLE "); + deparseRoleList(state, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(state, def_elem); + } +} + +static void deparseCreatePLangStmt(DeparseState *state, CreatePLangStmt *create_p_lang_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + + if (create_p_lang_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + deparseAppendStringInfoString(state, "TRUSTED "); + + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseNonReservedWordOrSconst(state, create_p_lang_stmt->plname); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_p_lang_stmt->plhandler); + deparseAppendStringInfoChar(state, ' '); + + if (create_p_lang_stmt->plinline) + { + deparseAppendStringInfoString(state, "INLINE "); + deparseHandlerName(state, create_p_lang_stmt->plinline); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + deparseAppendStringInfoString(state, "VALIDATOR "); + deparseHandlerName(state, create_p_lang_stmt->plvalidator); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseCreateRoleStmt(DeparseState *state, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case ROLESTMT_USER: + deparseAppendStringInfoString(state, "USER "); + break; + case ROLESTMT_GROUP: + deparseAppendStringInfoString(state, "GROUP "); + break; + } + + deparseAppendStringInfoString(state, quote_identifier(create_role_stmt->role)); + deparseAppendStringInfoChar(state, ' '); + + if (create_role_stmt->options != NULL) + { + deparseAppendStringInfoString(state, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseAlterRoleStmt(DeparseState *state, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + deparseAppendStringInfoString(state, "GROUP "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); + + if (alter_role_stmt->action == 1) + { + deparseAppendStringInfoString(state, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + deparseAppendStringInfoString(state, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(state, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + deparseAppendStringInfoString(state, "ROLE "); + deparseRoleSpec(state, alter_role_stmt->role); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(state, castNode(DefElem, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + removeTrailingSpace(state); +} + +static void deparseDeclareCursorStmt(DeparseState *state, DeclareCursorStmt *declare_cursor_stmt) +{ + deparseAppendStringInfoString(state, "DECLARE "); + deparseAppendStringInfoString(state, quote_identifier(declare_cursor_stmt->portalname)); + deparseAppendStringInfoChar(state, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + deparseAppendStringInfoString(state, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + deparseAppendStringInfoString(state, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + deparseAppendStringInfoString(state, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + deparseAppendStringInfoString(state, "INSENSITIVE "); + + deparseAppendStringInfoString(state, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + deparseAppendStringInfoString(state, "WITH HOLD "); + + deparseAppendStringInfoString(state, "FOR "); + + deparseSelectStmt(state, castNode(SelectStmt, declare_cursor_stmt->query), DEPARSE_NODE_CONTEXT_NONE); +} + +static void deparseFetchStmt(DeparseState *state, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + deparseAppendStringInfoString(state, "MOVE "); + else + deparseAppendStringInfoString(state, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + deparseAppendStringInfoString(state, "ALL "); + } + else + { + deparseAppendStringInfo(state, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + deparseAppendStringInfoString(state, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + deparseAppendStringInfoString(state, "BACKWARD ALL "); + } + else + { + deparseAppendStringInfo(state, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + deparseAppendStringInfoString(state, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + deparseAppendStringInfoString(state, "LAST "); + } + else + { + deparseAppendStringInfo(state, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + deparseAppendStringInfo(state, "RELATIVE %ld ", fetch_stmt->howMany); + } + + deparseAppendStringInfoString(state, quote_identifier(fetch_stmt->portalname)); +} + +static void deparseAlterDefaultPrivilegesStmt(DeparseState *state, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + deparseAppendStringInfoString(state, "IN SCHEMA "); + deparseNameList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + deparseAppendStringInfoString(state, "FOR ROLE "); + deparseRoleList(state, castNode(List, defelem->arg)); + deparseAppendStringInfoChar(state, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(state, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(DeparseState *state, ReindexStmt *reindex_stmt) +{ + deparseAppendStringInfoString(state, "REINDEX "); + + deparseUtilityOptionList(state, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + deparseAppendStringInfoString(state, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(state, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(DeparseState *state, RuleStmt* rule_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + if (rule_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseAppendStringInfoString(state, "RULE "); + deparseAppendStringInfoString(state, quote_identifier(rule_stmt->rulename)); + deparseAppendStringInfoString(state, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + deparseAppendStringInfoString(state, "SELECT "); + break; + case CMD_UPDATE: + deparseAppendStringInfoString(state, "UPDATE "); + break; + case CMD_INSERT: + deparseAppendStringInfoString(state, "INSERT "); + break; + case CMD_DELETE: + deparseAppendStringInfoString(state, "DELETE "); + break; + case CMD_MERGE: + deparseAppendStringInfoString(state, "MERGE "); + break; + } + + deparseAppendStringInfoString(state, "TO "); + deparseRangeVar(state, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseWhereClause(state, rule_stmt->whereClause); + + deparseAppendStringInfoString(state, "DO "); + + if (rule_stmt->instead) + deparseAppendStringInfoString(state, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + deparseAppendStringInfoString(state, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(state, linitial(rule_stmt->actions)); + } + else + { + deparseAppendStringInfoChar(state, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(state, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + deparseAppendStringInfoString(state, "; "); + } + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseNotifyStmt(DeparseState *state, NotifyStmt *notify_stmt) +{ + deparseAppendStringInfoString(state, "NOTIFY "); + deparseAppendStringInfoString(state, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseStringLiteral(state, notify_stmt->payload); + } +} + +static void deparseListenStmt(DeparseState *state, ListenStmt *listen_stmt) +{ + deparseAppendStringInfoString(state, "LISTEN "); + deparseAppendStringInfoString(state, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(DeparseState *state, UnlistenStmt *unlisten_stmt) +{ + deparseAppendStringInfoString(state, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + deparseAppendStringInfoString(state, "*"); + else + deparseAppendStringInfoString(state, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(DeparseState *state, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE "); + + deparseOptTemp(state, create_seq_stmt->sequence->relpersistence); + + deparseAppendStringInfoString(state, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseRangeVar(state, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseOptSeqOptList(state, create_seq_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterFunctionStmt(DeparseState *state, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(state, alter_function_stmt->func); + deparseAppendStringInfoChar(state, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(state, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + deparseAppendStringInfoChar(state, ' '); + } +} + +static void deparseTruncateStmt(DeparseState *state, TruncateStmt *truncate_stmt) +{ + deparseAppendStringInfoString(state, "TRUNCATE "); + + deparseRelationExprList(state, truncate_stmt->relations); + deparseAppendStringInfoChar(state, ' '); + + if (truncate_stmt->restart_seqs) + deparseAppendStringInfoString(state, "RESTART IDENTITY "); + + deparseOptDropBehavior(state, truncate_stmt->behavior); + + removeTrailingSpace(state); +} + +static void deparseCreateEventTrigStmt(DeparseState *state, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + deparseAppendStringInfoString(state, "CREATE EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "ON "); + deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->eventname)); + deparseAppendStringInfoChar(state, ' '); + + if (create_event_trig_stmt->whenclause) + { + deparseAppendStringInfoString(state, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(state, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + deparseAppendStringInfoString(state, " AND "); + } + + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_event_trig_stmt->funcname); + deparseAppendStringInfoString(state, "()"); +} + +static void deparseAlterEventTrigStmt(DeparseState *state, AlterEventTrigStmt *alter_event_trig_stmt) +{ + deparseAppendStringInfoString(state, "ALTER EVENT TRIGGER "); + deparseAppendStringInfoString(state, quote_identifier(alter_event_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + deparseAppendStringInfoString(state, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + deparseAppendStringInfoString(state, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + deparseAppendStringInfoString(state, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + deparseAppendStringInfoString(state, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(DeparseState *state, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + deparseAppendStringInfoString(state, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + deparseAppendStringInfoString(state, "CONCURRENTLY "); + + deparseRangeVar(state, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (refresh_mat_view_stmt->skipData) + deparseAppendStringInfoString(state, "WITH NO DATA "); + + removeTrailingSpace(state); +} + +static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + deparseAppendStringInfoString(state, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + deparseAppendStringInfoString(state, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + deparseAppendStringInfoString(state, "USING INDEX "); + deparseAppendStringInfoString(state, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +// "CreatePolicyStmt" in gram.y +static void deparseCreatePolicyStmt(DeparseState *state, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE POLICY "); + deparseColId(state, create_policy_stmt->policy_name); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (!create_policy_stmt->permissive) + deparseAppendStringInfoString(state, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + deparseAppendStringInfoString(state, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + deparseAppendStringInfoString(state, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + deparseAppendStringInfoString(state, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + deparseAppendStringInfoString(state, "FOR DELETE "); + else + Assert(false); + + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, create_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + + if (create_policy_stmt->qual != NULL) + { + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, create_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, create_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } +} + +// "AlterPolicyStmt" in gram.y +static void deparseAlterPolicyStmt(DeparseState *state, AlterPolicyStmt *alter_policy_stmt) +{ + deparseAppendStringInfoString(state, "ALTER POLICY "); + deparseAppendStringInfoString(state, quote_identifier(alter_policy_stmt->policy_name)); + deparseAppendStringInfoString(state, " ON "); + deparseRangeVar(state, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + deparseAppendStringInfoString(state, "TO "); + deparseRoleList(state, alter_policy_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + deparseAppendStringInfoString(state, "USING ("); + deparseExpr(state, alter_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + deparseAppendStringInfoString(state, "WITH CHECK ("); + deparseExpr(state, alter_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } +} + +static void deparseCreateTableSpaceStmt(DeparseState *state, CreateTableSpaceStmt *create_table_space_stmt) +{ + deparseAppendStringInfoString(state, "CREATE TABLESPACE "); + deparseColId(state, create_table_space_stmt->tablespacename); + deparseAppendStringInfoChar(state, ' '); + + if (create_table_space_stmt->owner != NULL) + { + deparseAppendStringInfoString(state, "OWNER "); + deparseRoleSpec(state, create_table_space_stmt->owner); + deparseAppendStringInfoChar(state, ' '); + } + + deparseAppendStringInfoString(state, "LOCATION "); + + if (create_table_space_stmt->location != NULL) + deparseStringLiteral(state, create_table_space_stmt->location); + else + deparseAppendStringInfoString(state, "''"); + + deparseAppendStringInfoChar(state, ' '); + + deparseOptWith(state, create_table_space_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseCreateTransformStmt(DeparseState *state, CreateTransformStmt *create_transform_stmt) +{ + deparseAppendStringInfoString(state, "CREATE "); + if (create_transform_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + + deparseAppendStringInfoString(state, "TRANSFORM FOR "); + deparseTypeName(state, create_transform_stmt->type_name); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(create_transform_stmt->lang)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoChar(state, '('); + + if (create_transform_stmt->fromsql) + { + deparseAppendStringInfoString(state, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + deparseAppendStringInfoString(state, ", "); + + if (create_transform_stmt->tosql) + { + deparseAppendStringInfoString(state, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(state, create_transform_stmt->tosql); + } + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseCreateAmStmt(DeparseState *state, CreateAmStmt *create_am_stmt) +{ + deparseAppendStringInfoString(state, "CREATE ACCESS METHOD "); + deparseAppendStringInfoString(state, quote_identifier(create_am_stmt->amname)); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case AMTYPE_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + } + + deparseAppendStringInfoString(state, "HANDLER "); + deparseHandlerName(state, create_am_stmt->handler_name); +} + +// "pub_obj_list" in gram.y +static void deparsePublicationObjectList(DeparseState *state, List *pubobjects) { + const ListCell *lc; + foreach(lc, pubobjects) { + PublicationObjSpec *obj = lfirst(lc); + + switch (obj->pubobjtype) { + case PUBLICATIONOBJ_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + deparseRangeVar(state, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + + if (obj->pubtable->columns) + { + deparseAppendStringInfoChar(state, '('); + deparseColumnList(state, obj->pubtable->columns); + deparseAppendStringInfoChar(state, ')'); + } + + if (obj->pubtable->whereClause) + { + deparseAppendStringInfoString(state, " WHERE ("); + deparseExpr(state, obj->pubtable->whereClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); + } + + break; + case PUBLICATIONOBJ_TABLES_IN_SCHEMA: + deparseAppendStringInfoString(state, "TABLES IN SCHEMA "); + deparseAppendStringInfoString(state, quote_identifier(obj->name)); + break; + case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: + deparseAppendStringInfoString(state, "TABLES IN SCHEMA CURRENT_SCHEMA"); + break; + case PUBLICATIONOBJ_CONTINUATION: + // This should be unreachable, the parser merges these before we can even get here. + Assert(false); + break; + } + + if (lnext(pubobjects, lc)) { + deparseAppendStringInfoString(state, ", "); + } + } +} + +static void deparseCreatePublicationStmt(DeparseState *state, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "CREATE PUBLICATION "); + deparseAppendStringInfoString(state, quote_identifier(create_publication_stmt->pubname)); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_publication_stmt->pubobjects) > 0) + { + deparseAppendStringInfoString(state, "FOR "); + deparsePublicationObjectList(state, create_publication_stmt->pubobjects); + deparseAppendStringInfoChar(state, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + deparseAppendStringInfoString(state, "FOR ALL TABLES "); + } + + deparseOptDefinition(state, create_publication_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterPublicationStmt(DeparseState *state, AlterPublicationStmt *alter_publication_stmt) +{ + deparseAppendStringInfoString(state, "ALTER PUBLICATION "); + deparseColId(state, alter_publication_stmt->pubname); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(alter_publication_stmt->pubobjects) > 0) + { + switch (alter_publication_stmt->action) + { + case AP_SetObjects: + deparseAppendStringInfoString(state, "SET "); + break; + case AP_AddObjects: + deparseAppendStringInfoString(state, "ADD "); + break; + case AP_DropObjects: + deparseAppendStringInfoString(state, "DROP "); + break; + } + + deparsePublicationObjectList(state, alter_publication_stmt->pubobjects); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(DeparseState *state, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseRangeVar(state, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + deparseSeqOptList(state, alter_seq_stmt->options); + + removeTrailingSpace(state); +} + +static void deparseAlterSystemStmt(DeparseState *state, AlterSystemStmt *alter_system_stmt) +{ + deparseAppendStringInfoString(state, "ALTER SYSTEM "); + deparseVariableSetStmt(state, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(DeparseState *state, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + deparseAppendStringInfoString(state, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + deparseAppendStringInfoString(state, "COLUMN "); + break; + case OBJECT_INDEX: + deparseAppendStringInfoString(state, "INDEX "); + break; + case OBJECT_SEQUENCE: + deparseAppendStringInfoString(state, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + break; + case OBJECT_TABLE: + deparseAppendStringInfoString(state, "TABLE "); + break; + case OBJECT_VIEW: + deparseAppendStringInfoString(state, "VIEW "); + break; + case OBJECT_MATVIEW: + deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + deparseAppendStringInfoString(state, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + deparseAppendStringInfoString(state, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + deparseAppendStringInfoString(state, "EXTENSION "); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + break; + case OBJECT_ROLE: + deparseAppendStringInfoString(state, "ROLE "); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + deparseAppendStringInfoString(state, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAppendStringInfoString(state, "CONSTRAINT "); + break; + case OBJECT_POLICY: + deparseAppendStringInfoString(state, "POLICY "); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + break; + case OBJECT_RULE: + deparseAppendStringInfoString(state, "RULE "); + break; + case OBJECT_TRANSFORM: + deparseAppendStringInfoString(state, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + deparseAppendStringInfoString(state, "TRIGGER "); + break; + case OBJECT_OPCLASS: + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + break; + case OBJECT_CAST: + deparseAppendStringInfoString(state, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(state, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(state, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON "); + deparseAnyNameSkipLast(state, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); + deparseAppendStringInfoString(state, " ON DOMAIN "); + deparseTypeName(state, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoString(state, "FOR "); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " LANGUAGE "); + deparseAppendStringInfoString(state, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(state, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + deparseAppendStringInfoChar(state, '('); + deparseTypeName(state, castNode(TypeName, linitial(l))); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, castNode(TypeName, lsecond(l))); + deparseAppendStringInfoChar(state, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + deparseAppendStringInfoString(state, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(state, comment_stmt->comment); + else + deparseAppendStringInfoString(state, "NULL"); +} + +// "stats_param" in gram.y +static void deparseStatsElem(DeparseState *state, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + deparseAppendStringInfoString(state, stats_elem->name); + else if (stats_elem->expr) + { + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, stats_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + } +} + +static void deparseCreateStatsStmt(DeparseState *state, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + deparseAppendStringInfoString(state, "IF NOT EXISTS "); + + deparseAnyName(state, create_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + deparseAppendStringInfoChar(state, '('); + deparseNameList(state, create_stats_stmt->stat_types); + deparseAppendStringInfoString(state, ") "); + } + + deparseAppendStringInfoString(state, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(state, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoString(state, " FROM "); + deparseFromList(state, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(DeparseState *state, AlterCollationStmt *alter_collation_stmt) +{ + deparseAppendStringInfoString(state, "ALTER COLLATION "); + deparseAnyName(state, alter_collation_stmt->collname); + deparseAppendStringInfoString(state, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(DeparseState *state, AlterDatabaseStmt *alter_database_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseCreatedbOptList(state, alter_database_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterDatabaseSetStmt(DeparseState *state, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + deparseAppendStringInfoString(state, "ALTER DATABASE "); + deparseColId(state, alter_database_set_stmt->dbname); + deparseAppendStringInfoChar(state, ' '); + deparseVariableSetStmt(state, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(DeparseState *state, AlterStatsStmt *alter_stats_stmt) +{ + deparseAppendStringInfoString(state, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAnyName(state, alter_stats_stmt->defnames); + deparseAppendStringInfoChar(state, ' '); + + if (alter_stats_stmt->stxstattarget) + deparseAppendStringInfo(state, "SET STATISTICS %d", castNode(Integer, alter_stats_stmt->stxstattarget)->ival); + else + deparseAppendStringInfo(state, "SET STATISTICS DEFAULT"); +} + +static void deparseAlterTSDictionaryStmt(DeparseState *state, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(state, alter_ts_dictionary_stmt->dictname); + deparseAppendStringInfoChar(state, ' '); + + deparseDefinition(state, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(DeparseState *state, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + deparseAppendStringInfoString(state, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, alter_ts_configuration_stmt->cfgname); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + deparseAppendStringInfoString(state, "ADD MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + deparseAppendStringInfoString(state, "ALTER MAPPING REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + deparseAppendStringInfoString(state, " REPLACE "); + deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); + deparseAppendStringInfoString(state, " WITH "); + deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + deparseAppendStringInfoString(state, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + deparseAppendStringInfoString(state, "FOR "); + deparseNameList(state, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(DeparseState *state, VariableShowStmt *variable_show_stmt) +{ + deparseAppendStringInfoString(state, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + deparseAppendStringInfoString(state, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + deparseAppendStringInfoString(state, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + deparseAppendStringInfoString(state, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + deparseAppendStringInfoString(state, "ALL"); + else + deparseAppendStringInfoString(state, quote_identifier(variable_show_stmt->name)); +} + +// "tablesample_clause" in gram.y +static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample) +{ + deparseRangeVar(state, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + deparseAppendStringInfoString(state, " TABLESAMPLE "); + + deparseFuncName(state, range_table_sample->method); + deparseAppendStringInfoChar(state, '('); + deparseExprList(state, range_table_sample->args); + deparseAppendStringInfoString(state, ") "); + + if (range_table_sample->repeatable != NULL) + { + deparseAppendStringInfoString(state, "REPEATABLE ("); + deparseExpr(state, range_table_sample->repeatable, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + removeTrailingSpace(state); +} + +static void deparseCreateSubscriptionStmt(DeparseState *state, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "CREATE SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(create_subscription_stmt->subname)); + + deparseAppendStringInfoString(state, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(state, create_subscription_stmt->conninfo); + else + deparseAppendStringInfoString(state, "''"); + + deparseAppendStringInfoString(state, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + + deparseOptDefinition(state, create_subscription_stmt->options); + removeTrailingSpace(state); +} + +static void deparseAlterSubscriptionStmt(DeparseState *state, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + deparseAppendStringInfoString(state, "ALTER SUBSCRIPTION "); + deparseAppendStringInfoString(state, quote_identifier(alter_subscription_stmt->subname)); + deparseAppendStringInfoChar(state, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + deparseAppendStringInfoString(state, "SET "); + deparseDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SKIP: + deparseAppendStringInfoString(state, "SKIP "); + deparseDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + deparseAppendStringInfoString(state, "CONNECTION "); + deparseStringLiteral(state, alter_subscription_stmt->conninfo); + deparseAppendStringInfoChar(state, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + deparseAppendStringInfoString(state, "REFRESH PUBLICATION "); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + deparseAppendStringInfoString(state, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + deparseAppendStringInfoString(state, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + deparseAppendStringInfoString(state, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(state, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); + deparseOptDefinition(state, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (optBooleanValue(defelem->arg)) + { + deparseAppendStringInfoString(state, " ENABLE "); + } + else + { + deparseAppendStringInfoString(state, " DISABLE "); + } + break; + } + + removeTrailingSpace(state); +} + +static void deparseDropSubscriptionStmt(DeparseState *state, DropSubscriptionStmt *drop_subscription_stmt) +{ + deparseAppendStringInfoString(state, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + deparseAppendStringInfoString(state, "IF EXISTS "); + + deparseAppendStringInfoString(state, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(DeparseState *state, CallStmt *call_stmt) +{ + deparseAppendStringInfoString(state, "CALL "); + deparseFuncCall(state, call_stmt->funccall, DEPARSE_NODE_CONTEXT_NONE); +} + +static void deparseAlterOwnerStmt(DeparseState *state, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + deparseAppendStringInfoString(state, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + deparseAppendStringInfoString(state, "AGGREGATE "); + deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + deparseAppendStringInfoString(state, "COLLATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + deparseAppendStringInfoString(state, "CONVERSION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + deparseAppendStringInfoString(state, "DATABASE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + deparseAppendStringInfoString(state, "DOMAIN "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + deparseAppendStringInfoString(state, "FUNCTION "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + deparseAppendStringInfoString(state, "LANGUAGE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + deparseAppendStringInfoString(state, "LARGE OBJECT "); + deparseNumericOnly(state, (union ValUnion *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + deparseAppendStringInfoString(state, "OPERATOR "); + deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + deparseAppendStringInfoString(state, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(state, l); + deparseAppendStringInfoString(state, " USING "); + deparseColId(state, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + deparseAppendStringInfoString(state, "PROCEDURE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + deparseAppendStringInfoString(state, "ROUTINE "); + deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + deparseAppendStringInfoString(state, "SCHEMA "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + deparseAppendStringInfoString(state, "TYPE "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + deparseAppendStringInfoString(state, "TABLESPACE "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + deparseAppendStringInfoString(state, "STATISTICS "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(state, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + deparseAppendStringInfoString(state, "SERVER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + deparseAppendStringInfoString(state, "EVENT TRIGGER "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + deparseAppendStringInfoString(state, "PUBLICATION "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + deparseAppendStringInfoString(state, "SUBSCRIPTION "); + deparseColId(state, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + deparseAppendStringInfoString(state, " OWNER TO "); + deparseRoleSpec(state, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(DeparseState *state, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); + deparseAppendStringInfoString(state, " = "); + if (def_elem->arg != NULL) + deparseDefArg(state, def_elem->arg, true); + else + deparseAppendStringInfoString(state, "NONE"); + + if (lnext(defs, lc)) + deparseAppendStringInfoString(state, ", "); + } +} + +static void deparseAlterOperatorStmt(DeparseState *state, AlterOperatorStmt *alter_operator_stmt) +{ + deparseAppendStringInfoString(state, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(state, alter_operator_stmt->opername); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_operator_stmt->options); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseAlterTypeStmt(DeparseState *state, AlterTypeStmt *alter_type_stmt) +{ + deparseAppendStringInfoString(state, "ALTER TYPE "); + deparseAnyName(state, alter_type_stmt->typeName); + deparseAppendStringInfoString(state, " SET ("); + deparseOperatorDefList(state, alter_type_stmt->options); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseDropOwnedStmt(DeparseState *state, DropOwnedStmt *drop_owned_stmt) +{ + deparseAppendStringInfoString(state, "DROP OWNED BY "); + deparseRoleList(state, drop_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + deparseOptDropBehavior(state, drop_owned_stmt->behavior); + removeTrailingSpace(state); +} + +static void deparseReassignOwnedStmt(DeparseState *state, ReassignOwnedStmt *reassigned_owned_stmt) +{ + deparseAppendStringInfoString(state, "REASSIGN OWNED BY "); + + deparseRoleList(state, reassigned_owned_stmt->roles); + deparseAppendStringInfoChar(state, ' '); + + deparseAppendStringInfoString(state, "TO "); + deparseRoleSpec(state, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(DeparseState *state, ClosePortalStmt *close_portal_stmt) +{ + deparseAppendStringInfoString(state, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + deparseAppendStringInfoString(state, quote_identifier(close_portal_stmt->portalname)); + } + else + { + deparseAppendStringInfoString(state, "ALL"); + } +} + +// "CreateTrigStmt" in gram.y +static void deparseCreateTrigStmt(DeparseState *state, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + deparseAppendStringInfoString(state, "CREATE "); + if (create_trig_stmt->replace) + deparseAppendStringInfoString(state, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + deparseAppendStringInfoString(state, "CONSTRAINT "); + deparseAppendStringInfoString(state, "TRIGGER "); + + deparseAppendStringInfoString(state, quote_identifier(create_trig_stmt->trigname)); + deparseAppendStringInfoChar(state, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + deparseAppendStringInfoString(state, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + deparseAppendStringInfoString(state, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + deparseAppendStringInfoString(state, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + deparseAppendStringInfoString(state, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + deparseAppendStringInfoString(state, "OF "); + deparseColumnList(state, create_trig_stmt->columns); + deparseAppendStringInfoChar(state, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + deparseAppendStringInfoString(state, "OR "); + deparseAppendStringInfoString(state, "TRUNCATE "); + } + + deparseAppendStringInfoString(state, "ON "); + deparseRangeVar(state, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + deparseAppendStringInfoString(state, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(state, castNode(TriggerTransition, lfirst(lc))); + deparseAppendStringInfoChar(state, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + deparseAppendStringInfoString(state, "FROM "); + deparseRangeVar(state, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (create_trig_stmt->deferrable) + deparseAppendStringInfoString(state, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + deparseAppendStringInfoString(state, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + deparseAppendStringInfoString(state, "WHEN ("); + deparseExpr(state, create_trig_stmt->whenClause, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); + deparseFuncName(state, create_trig_stmt->funcname); + deparseAppendStringInfoChar(state, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(state, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + deparseAppendStringInfoString(state, "NEW "); + else + deparseAppendStringInfoString(state, "OLD "); + + if (trigger_transition->isTable) + deparseAppendStringInfoString(state, "TABLE "); + else + deparseAppendStringInfoString(state, "ROW "); + + deparseAppendStringInfoString(state, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + deparseAppendStringInfoString(state, "xmlconcat("); + deparseExprList(state, xml_expr->args); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + deparseAppendStringInfoString(state, "xmlelement(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + deparseAppendStringInfoString(state, ", xmlattributes("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoString(state, ")"); + } + if (xml_expr->args != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseExprList(state, xml_expr->args); + } + deparseAppendStringInfoString(state, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + deparseAppendStringInfoString(state, "xmlforest("); + deparseXmlAttributeList(state, xml_expr->named_args); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + deparseAppendStringInfoString(state, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + deparseAppendStringInfoString(state, "document "); + break; + case XMLOPTION_CONTENT: + deparseAppendStringInfoString(state, "content "); + break; + default: + Assert(false); + } + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + deparseAppendStringInfoString(state, "xmlpi(name "); + deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + } + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + deparseAppendStringInfoString(state, "xmlroot("); + deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ", version "); + if (castNode(A_Const, lsecond(xml_expr->args))->isnull) + deparseAppendStringInfoString(state, "no value"); + else + deparseExpr(state, lsecond(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + deparseAppendStringInfoString(state, ", standalone yes"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + deparseAppendStringInfoString(state, ", standalone no"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + deparseAppendStringInfoString(state, ", standalone no value"); + deparseAppendStringInfoChar(state, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(state, linitial(xml_expr->args), context); + deparseAppendStringInfoString(state, " IS DOCUMENT"); + break; + } +} + +// "xmltable_column_el" in gram.y +static void deparseRangeTableFuncCol(DeparseState *state, RangeTableFuncCol* range_table_func_col) +{ + deparseAppendStringInfoString(state, quote_identifier(range_table_func_col->colname)); + deparseAppendStringInfoChar(state, ' '); + + if (range_table_func_col->for_ordinality) + { + deparseAppendStringInfoString(state, "FOR ORDINALITY "); + } + else + { + deparseTypeName(state, range_table_func_col->typeName); + deparseAppendStringInfoChar(state, ' '); + + if (range_table_func_col->colexpr) + { + deparseAppendStringInfoString(state, "PATH "); + deparseExpr(state, range_table_func_col->colexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); + } + + if (range_table_func_col->coldefexpr) + { + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, range_table_func_col->coldefexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); + deparseAppendStringInfoChar(state, ' '); + } + + if (range_table_func_col->is_not_null) + deparseAppendStringInfoString(state, "NOT NULL "); + } + + removeTrailingSpace(state); +} + +// "table_ref" and "xmltable" in gram.y +static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + deparseAppendStringInfoString(state, "LATERAL "); + + deparseAppendStringInfoString(state, "xmltable("); + if (range_table_func->namespaces) + { + deparseAppendStringInfoString(state, "xmlnamespaces("); + deparseXmlNamespaceList(state, range_table_func->namespaces); + deparseAppendStringInfoString(state, "), "); + } + + deparseAppendStringInfoChar(state, '('); + deparseExpr(state, range_table_func->rowexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + deparseAppendStringInfoChar(state, ')'); + + deparseAppendStringInfoString(state, " PASSING "); + deparseExpr(state, range_table_func->docexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); + + deparseAppendStringInfoString(state, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(state, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoString(state, ") "); + + if (range_table_func->alias) + { + deparseAppendStringInfoString(state, "AS "); + deparseAlias(state, range_table_func->alias); + } + + removeTrailingSpace(state); +} + +static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize) +{ + deparseAppendStringInfoString(state, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + deparseAppendStringInfoString(state, "document "); + break; + case XMLOPTION_CONTENT: + deparseAppendStringInfoString(state, "content "); + break; + default: + Assert(false); + } + deparseExpr(state, xml_serialize->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, " AS "); + deparseTypeName(state, xml_serialize->typeName); + + if (xml_serialize->indent) { + deparseAppendStringInfoString(state, " INDENT"); + } + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonFormat(DeparseState *state, JsonFormat *json_format) +{ + if (json_format == NULL || json_format->format_type == JS_FORMAT_DEFAULT) + return; + + deparseAppendStringInfoString(state, "FORMAT JSON "); + + switch (json_format->encoding) + { + case JS_ENC_UTF8: + deparseAppendStringInfoString(state, "ENCODING utf8 "); + break; + case JS_ENC_UTF16: + deparseAppendStringInfoString(state, "ENCODING utf16 "); + break; + case JS_ENC_UTF32: + deparseAppendStringInfoString(state, "ENCODING utf32 "); + break; + case JS_ENC_DEFAULT: + // no encoding specified + break; + } +} + +static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *j) +{ + deparseExpr(state, j->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + + deparseJsonFormat(state, castNode(JsonFormat, j->format)); + + deparseAppendStringInfoString(state, "IS "); + + switch (j->item_type) + { + case JS_TYPE_ANY: + deparseAppendStringInfoString(state, "JSON "); + break; + case JS_TYPE_ARRAY: + deparseAppendStringInfoString(state, "JSON ARRAY "); + break; + case JS_TYPE_OBJECT: + deparseAppendStringInfoString(state, "JSON OBJECT "); + break; + case JS_TYPE_SCALAR: + deparseAppendStringInfoString(state, "JSON SCALAR "); + break; + } + + if (j->unique_keys) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + removeTrailingSpace(state); +} + +// "json_value_expr" in gram.y +static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr) +{ + deparseExpr(state, (Node *) json_value_expr->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_value_expr->format); +} + +// "json_value_expr_list" in gram.y +static void deparseJsonValueExprList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonValueExpr(state, lfirst(lc)); + removeTrailingSpace(state); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); +} + +// "json_name_and_value" in gram.y +static void deparseJsonKeyValue(DeparseState *state, JsonKeyValue *json_key_value) +{ + deparseExpr(state, (Node *) json_key_value->key, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ": "); + deparseJsonValueExpr(state, json_key_value->value); +} + +// "json_name_and_value_list" in gram.y +static void deparseJsonKeyValueList(DeparseState *state, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseJsonKeyValue(state, lfirst(lc)); + removeTrailingSpace(state); + if (lnext(exprs, lc)) + deparseAppendStringInfoString(state, ", "); + } + deparseAppendStringInfoChar(state, ' '); +} + +static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output) +{ + if (json_output == NULL) + return; + + Assert(json_output->returning != NULL); + + deparseAppendStringInfoString(state, "RETURNING "); + deparseTypeName(state, json_output->typeName); + deparseAppendStringInfoChar(state, ' '); + deparseJsonFormat(state, json_output->returning->format); +} + +// "json_aggregate_func" and "func_expr" in gram.y +static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg) +{ + Assert(json_object_agg->constructor != NULL); + + deparseAppendStringInfoString(state, "JSON_OBJECTAGG("); + deparseJsonKeyValue(state, json_object_agg->arg); + + if (json_object_agg->absent_on_null) + deparseAppendStringInfoString(state, "ABSENT ON NULL "); + + if (json_object_agg->unique) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + deparseJsonOutput(state, json_object_agg->constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (json_object_agg->constructor->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_object_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (json_object_agg->constructor->over) + { + struct WindowDef *over = json_object_agg->constructor->over; + deparseAppendStringInfoString(state, "OVER "); + if (over->name) + deparseAppendStringInfoString(state, over->name); + else + deparseWindowDef(state, over); + } + + removeTrailingSpace(state); +} + +// "json_aggregate_func" and "func_expr" in gram.y +static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg) +{ + Assert(json_array_agg->constructor != NULL); + + deparseAppendStringInfoString(state, "JSON_ARRAYAGG("); + deparseJsonValueExpr(state, json_array_agg->arg); + deparseOptSortClause(state, json_array_agg->constructor->agg_order, DEPARSE_NODE_CONTEXT_NONE); + + if (!json_array_agg->absent_on_null) + deparseAppendStringInfoString(state, "NULL ON NULL "); + + deparseJsonOutput(state, json_array_agg->constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoString(state, ") "); + + if (json_array_agg->constructor->agg_filter) + { + deparseAppendStringInfoString(state, "FILTER (WHERE "); + deparseExpr(state, json_array_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ") "); + } + + if (json_array_agg->constructor->over) + { + struct WindowDef *over = json_array_agg->constructor->over; + deparseAppendStringInfoString(state, "OVER "); + if (over->name) + deparseAppendStringInfoString(state, over->name); + else + deparseWindowDef(state, over); + } + + removeTrailingSpace(state); +} + +static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor) +{ + deparseAppendStringInfoString(state, "JSON_OBJECT("); + deparseJsonKeyValueList(state, json_object_constructor->exprs); + + if (json_object_constructor->absent_on_null) + deparseAppendStringInfoString(state, "ABSENT ON NULL "); + + if (json_object_constructor->unique) + deparseAppendStringInfoString(state, "WITH UNIQUE "); + + deparseJsonOutput(state, json_object_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor) +{ + deparseAppendStringInfoString(state, "JSON_ARRAY("); + deparseJsonValueExprList(state, json_array_constructor->exprs); + + if (!json_array_constructor->absent_on_null) + deparseAppendStringInfoString(state, "NULL ON NULL "); + + deparseJsonOutput(state, json_array_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor) +{ + deparseAppendStringInfoString(state, "JSON_ARRAY("); + + deparseSelectStmt(state, castNode(SelectStmt, json_array_query_constructor->query), DEPARSE_NODE_CONTEXT_NONE); + deparseJsonFormat(state, json_array_query_constructor->format); + deparseJsonOutput(state, json_array_query_constructor->output); + + removeTrailingSpace(state); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr) +{ + deparseAppendStringInfoString(state, "JSON("); + + deparseJsonValueExpr(state, json_parse_expr->expr); + + if (json_parse_expr->unique_keys) + deparseAppendStringInfoString(state, " WITH UNIQUE KEYS"); + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr) +{ + deparseAppendStringInfoString(state, "JSON_SCALAR("); + deparseExpr(state, (Node*) json_scalar_expr->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr) +{ + deparseAppendStringInfoString(state, "JSON_SERIALIZE("); + + deparseJsonValueExpr(state, json_serialize_expr->expr); + + if (json_serialize_expr->output) + deparseJsonOutput(state, json_serialize_expr->output); + + deparseAppendStringInfoString(state, ")"); +} + +static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes) +{ + switch (quotes) + { + case JS_QUOTES_UNSPEC: + break; + case JS_QUOTES_KEEP: + deparseAppendStringInfoString(state, " KEEP QUOTES"); + break; + case JS_QUOTES_OMIT: + deparseAppendStringInfoString(state, " OMIT QUOTES"); + break; + } +} + +static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior) +{ + if (!behavior) + return; + + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON ERROR"); +} + +static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior) +{ + if (behavior) + { + deparseAppendStringInfoChar(state, ' '); + deparseJsonBehavior(state, behavior); + deparseAppendStringInfoString(state, " ON EMPTY"); + } +} + +static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr) +{ + switch (json_func_expr->op) + { + case JSON_EXISTS_OP: + deparseAppendStringInfoString(state, "JSON_EXISTS("); + break; + case JSON_QUERY_OP: + deparseAppendStringInfoString(state, "JSON_QUERY("); + break; + case JSON_VALUE_OP: + deparseAppendStringInfoString(state, "JSON_VALUE("); + break; + case JSON_TABLE_OP: + deparseAppendStringInfoString(state, "JSON_TABLE("); + break; + } + + deparseJsonValueExpr(state, json_func_expr->context_item); + deparseAppendStringInfoString(state, ", "); + deparseExpr(state, json_func_expr->pathspec, DEPARSE_NODE_CONTEXT_A_EXPR); + + if (json_func_expr->passing) + deparseAppendStringInfoString(state, " PASSING "); + + ListCell *lc = NULL; + foreach (lc, json_func_expr->passing) + { + JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); + + if (lnext(json_func_expr->passing, lc)) + deparseAppendStringInfoString(state, ", "); + } + + if (json_func_expr->output) + { + deparseAppendStringInfoChar(state, ' '); + deparseJsonOutput(state, json_func_expr->output); + } + + switch (json_func_expr->wrapper) + { + case JSW_UNSPEC: + break; + case JSW_NONE: + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); + break; + case JSW_CONDITIONAL: + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); + break; + case JSW_UNCONDITIONAL: + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); + break; + } + + deparseJsonQuotesClauseOpt(state, json_func_expr->quotes); + deparseJsonOnEmptyClauseOpt(state, json_func_expr->on_empty); + deparseJsonOnErrorClauseOpt(state, json_func_expr->on_error); + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec) +{ + deparseStringLiteral(state, castNode(A_Const, json_table_path_spec->string)->val.sval.sval); + + if (json_table_path_spec->name) + { + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_table_path_spec->name); + } +} + +// "json_behavior" in gram.y +static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior) +{ + switch (json_behavior->btype) + { + case JSON_BEHAVIOR_NULL: + deparseAppendStringInfoString(state, "NULL"); + break; + case JSON_BEHAVIOR_ERROR: + deparseAppendStringInfoString(state, "ERROR"); + break; + case JSON_BEHAVIOR_EMPTY: + deparseAppendStringInfoString(state, "EMPTY"); + break; + case JSON_BEHAVIOR_TRUE: + deparseAppendStringInfoString(state, "TRUE"); + break; + case JSON_BEHAVIOR_FALSE: + deparseAppendStringInfoString(state, "FALSE"); + break; + case JSON_BEHAVIOR_EMPTY_ARRAY: + deparseAppendStringInfoString(state, "EMPTY ARRAY"); + break; + case JSON_BEHAVIOR_EMPTY_OBJECT: + deparseAppendStringInfoString(state, "EMPTY OBJECT"); + break; + case JSON_BEHAVIOR_DEFAULT: + deparseAppendStringInfoString(state, "DEFAULT "); + deparseExpr(state, (Node*) json_behavior->expr, DEPARSE_NODE_CONTEXT_A_EXPR); + break; + case JSON_BEHAVIOR_UNKNOWN: + deparseAppendStringInfoString(state, "UNKNOWN"); + break; + } +} + +static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column) +{ + if (json_table_column->coltype == JTC_NESTED) + { + deparseAppendStringInfoString(state, "NESTED PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); + deparseJsonTableColumns(state, json_table_column->columns); + return; + } + + deparseColLabel(state, json_table_column->name); + deparseAppendStringInfoChar(state, ' '); + + switch (json_table_column->coltype) + { + case JTC_FOR_ORDINALITY: + deparseAppendStringInfoString(state, " FOR ORDINALITY"); + break; + case JTC_EXISTS: + case JTC_FORMATTED: + case JTC_REGULAR: + deparseTypeName(state, json_table_column->typeName); + + if (json_table_column->coltype == JTC_EXISTS) + deparseAppendStringInfoString(state, " EXISTS "); + else + deparseAppendStringInfoChar(state, ' '); + + if (json_table_column->format) + deparseJsonFormat(state, json_table_column->format); + + if (json_table_column->pathspec) + { + deparseAppendStringInfoString(state, "PATH "); + deparseJsonTablePathSpec(state, json_table_column->pathspec); + } + break; + case JTC_NESTED: + Assert(false); + } + + switch (json_table_column->wrapper) + { + case JSW_UNSPEC: + break; + case JSW_NONE: + if (json_table_column->coltype == JTC_REGULAR || json_table_column->coltype == JTC_FORMATTED) + deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); + break; + case JSW_CONDITIONAL: + deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); + break; + case JSW_UNCONDITIONAL: + deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); + break; + } + + deparseJsonQuotesClauseOpt(state, json_table_column->quotes); + deparseJsonOnEmptyClauseOpt(state, json_table_column->on_empty); + deparseJsonOnErrorClauseOpt(state, json_table_column->on_error); +} + +static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns) +{ + deparseAppendStringInfoString(state, " COLUMNS ("); + + ListCell *lc = NULL; + foreach(lc, json_table_columns) + { + deparseJsonTableColumn(state, castNode(JsonTableColumn, lfirst(lc))); + + if (lnext(json_table_columns, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseJsonTable(DeparseState *state, JsonTable *json_table) +{ + deparseAppendStringInfoString(state, "JSON_TABLE("); + + deparseJsonValueExpr(state, json_table->context_item); + deparseAppendStringInfoString(state, ", "); + deparseJsonTablePathSpec(state, json_table->pathspec); + + if (json_table->passing) + deparseAppendStringInfoString(state, " PASSING "); + + ListCell *lc = NULL; + foreach (lc, json_table->passing) + { + JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); + deparseJsonValueExpr(state, json_argument->val); + deparseAppendStringInfoString(state, " AS "); + deparseColLabel(state, json_argument->name); + + if (lnext(json_table->passing, lc)) + deparseAppendStringInfoString(state, ", "); + } + + deparseJsonTableColumns(state, json_table->columns); + + if (json_table->on_error) + { + deparseJsonBehavior(state, json_table->on_error); + deparseAppendStringInfoString(state, " ON ERROR"); + } + + deparseAppendStringInfoChar(state, ')'); + + if (json_table->alias) + { + deparseAppendStringInfoChar(state, ' '); + deparseAlias(state, json_table->alias); + } +} + +static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func) +{ + deparseAppendStringInfoString(state, "GROUPING("); + deparseExprList(state, grouping_func->args); + deparseAppendStringInfoChar(state, ')'); +} + +static void deparseClusterStmt(DeparseState *state, ClusterStmt *cluster_stmt) +{ + deparseAppendStringInfoString(state, "CLUSTER "); + + deparseUtilityOptionList(state, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(state, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + deparseAppendStringInfoChar(state, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + deparseAppendStringInfoString(state, "USING "); + deparseAppendStringInfoString(state, quote_identifier(cluster_stmt->indexname)); + deparseAppendStringInfoChar(state, ' '); + } + + removeTrailingSpace(state); +} + +static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context) +{ + if (!value) { + deparseAppendStringInfoString(state, "NULL"); + return; + } + + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(state, value); + break; + case T_Boolean: + deparseAppendStringInfoString(state, value->boolval.boolval ? "true" : "false"); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + deparseAppendStringInfoString(state, quote_identifier(value->sval.sval)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(state, value->sval.sval); + } else { + deparseAppendStringInfoString(state, value->sval.sval); + } + break; + case T_BitString: + if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') + { + deparseAppendStringInfoChar(state, 'x'); + deparseStringLiteral(state, value->sval.sval + 1); + } + else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') + { + deparseAppendStringInfoChar(state, 'b'); + deparseStringLiteral(state, value->sval.sval + 1); + } + else + { + Assert(false); + } + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(state, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(DeparseState *state, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(state, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(state, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(state, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(state, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(DeparseState *state, Node *node) +{ + DeparseStateNestingLevel *parent_level = NULL; + + // For statements that can be nested, push/pop is handled directly in the + // respective deparse...Stmt methods + bool skip_push_pop = IsA(node, SelectStmt) || + IsA(node, InsertStmt) || + IsA(node, UpdateStmt) || + IsA(node, DeleteStmt) || + IsA(node, MergeStmt); + + if (!skip_push_pop) + parent_level = deparseStateIncreaseNestingLevel(state); + + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(state, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(state, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(state, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(state, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(state, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(state, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(state, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(state, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(state, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(state, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(state, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(state, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(state, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(state, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(state, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(state, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(state, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(state, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(state, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(state, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableMoveAllStmt: + deparseAlterTableMoveAllStmt(state, castNode(AlterTableMoveAllStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(state, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(state, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(state, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(state, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(state, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(state, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(state, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(state, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(state, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(state, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(state, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(state, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(state, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(state, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(state, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(state, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(state, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(state, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(state, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(state, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(state, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(state, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(state, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(state, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(state, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(state, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(state, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(state, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(state, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(state, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(state, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(state, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(state, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(state, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(state, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(state, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(state, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(state, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(state, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(state, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(state, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(state, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(state, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(state, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(state, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(state, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(state, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(state, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(state, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(state, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(state, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(state, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(state, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(state, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(state, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(state, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(state, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(state, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(state, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(state, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(state, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(state, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(state, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(state, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(state, castNode(LockStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(state, castNode(MergeStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(state, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(state, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(state, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(state, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(state, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(state, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(state, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_TransactionStmt: + deparseTransactionStmt(state, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(state, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(state, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(state, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(state, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(state, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(state, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(state, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(state, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(state, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(state, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } + + if (!skip_push_pop) + deparseStateDecreaseNestingLevel(state, parent_level); +} +#endif diff --git a/postgres_deparse.c b/src/postgres_deparse.18.c similarity index 99% rename from postgres_deparse.c rename to src/postgres_deparse.18.c index fe8566b..4f56f9a 100644 --- a/postgres_deparse.c +++ b/src/postgres_deparse.18.c @@ -1,4 +1,7 @@ -// From https://github.com/pganalyze/libpg_query/tree/156705b347d347c154fdfddf9341c07a9fa73dc2 +#include "pg_config.h" +#if(PG_MAJORVERSION_NUM == 18) + +// From https://github.com/pganalyze/libpg_query/blob/18.0.0/src/postgres_deparse.c // Copyright (c) 2015, Lukas Fittl // Copyright (c) 2016-2023, Duboce Labs, Inc. (pganalyze) @@ -12251,3 +12254,4 @@ static void deparseStmt(DeparseState *state, Node *node) if (!skip_push_pop) deparseStateDecreaseNestingLevel(state, parent_level); } +#endif diff --git a/postgres_deparse.h b/src/postgres_deparse.h similarity index 95% rename from postgres_deparse.h rename to src/postgres_deparse.h index 3506aac..e69c696 100644 --- a/postgres_deparse.h +++ b/src/postgres_deparse.h @@ -61,6 +61,10 @@ typedef struct StringInfoData *StringInfo; struct RawStmt; extern void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt); +#if (PG_MAJORVERSION_NUM >= 18) extern void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts *opts); +#elif (PG_MAJORVERSION_NUM >= 17) +extern void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts opts); +#endif #endif \ No newline at end of file From 119062b15925d48c05b1d22b3f0afabd3327336c Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 10:02:37 -0500 Subject: [PATCH 4/7] Fix multi expected for old psql --- expected/06_multi.out | 10 ---------- expected/06_multi_1.out | 24 ++++++++++++------------ expected/34_multi.out | 10 ---------- expected/34_multi_1.out | 24 ++++++++++++------------ 4 files changed, 24 insertions(+), 44 deletions(-) diff --git a/expected/06_multi.out b/expected/06_multi.out index e58b38b..91f11f4 100644 --- a/expected/06_multi.out +++ b/expected/06_multi.out @@ -7,8 +7,6 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE -INSERT 0 3 DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); INSERT INTO foobar.foo (id) VALUES (1),(2),(3); DROP TABLE foobar.foo;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled @@ -19,8 +17,6 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE -INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent @@ -56,16 +52,12 @@ SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -BEGIN -CREATE TABLE COMMIT \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -BEGIN -CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent @@ -106,14 +98,12 @@ DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent diff --git a/expected/06_multi_1.out b/expected/06_multi_1.out index a37f8ac..e58b38b 100644 --- a/expected/06_multi_1.out +++ b/expected/06_multi_1.out @@ -23,18 +23,18 @@ CREATE TABLE INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------+--------------------------- + test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; diff --git a/expected/34_multi.out b/expected/34_multi.out index e58b38b..91f11f4 100644 --- a/expected/34_multi.out +++ b/expected/34_multi.out @@ -7,8 +7,6 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE -INSERT 0 3 DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); INSERT INTO foobar.foo (id) VALUES (1),(2),(3); DROP TABLE foobar.foo;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled @@ -19,8 +17,6 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE -INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent @@ -56,16 +52,12 @@ SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -BEGIN -CREATE TABLE COMMIT \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -BEGIN -CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent @@ -106,14 +98,12 @@ DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foo(id int primary key); DROP TABLE foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE DROP TABLE \! PGOPTIONS='--client-min-messages=warning' psql -d contrib_regression -c "CREATE TABLE foobar.foo(id int primary key); DROP TABLE foobar.foo CASCADE;" WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled -CREATE TABLE DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; set_name | ddl_sql_raw | ddl_sql_sent diff --git a/expected/34_multi_1.out b/expected/34_multi_1.out index a37f8ac..e58b38b 100644 --- a/expected/34_multi_1.out +++ b/expected/34_multi_1.out @@ -23,18 +23,18 @@ CREATE TABLE INSERT 0 3 DROP TABLE SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-----------------------------+----------------------------- - test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; - test8 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; - test7 | DROP SCHEMA foobar CASCADE; | DROP SCHEMA foobar CASCADE; + set_name | ddl_sql_raw | ddl_sql_sent +----------+---------------------------+--------------------------- + test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test5 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test4 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test3 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test2 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test1 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; + test8 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; + test7 | DROP SEQUENCE foobar.foo; | DROP SEQUENCE foobar.foo; (10 rows) SELECT set_name, ddl_sql_raw, command_tag, reason FROM pgl_ddl_deploy.unhandled ORDER BY id DESC LIMIT 10; From 47d3aef621162e9d758fcf353290d9a79b472fdb Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 10:19:12 -0500 Subject: [PATCH 5/7] Make PG 11 and 12 happy --- expected/06_multi.out | 16 +- expected/06_multi_1.out | 16 +- expected/24_sub_retries.out | 12 +- expected/34_multi.out | 16 +- expected/34_multi_1.out | 16 +- expected/52_sub_retries.out | 12 +- src/pgl_ddl_deploy.c | 11 +- src/postgres_deparse.11.c | 9856 +++++++++++++++++++++++++++++++++- src/postgres_deparse.12.c | 9865 ++++++++++++++++++++++++++++++++++- 9 files changed, 19769 insertions(+), 51 deletions(-) diff --git a/expected/06_multi.out b/expected/06_multi.out index 91f11f4..2065aa5 100644 --- a/expected/06_multi.out +++ b/expected/06_multi.out @@ -60,14 +60,14 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------+----------------------------------------------- + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; diff --git a/expected/06_multi_1.out b/expected/06_multi_1.out index e58b38b..a9254db 100644 --- a/expected/06_multi_1.out +++ b/expected/06_multi_1.out @@ -68,14 +68,14 @@ BEGIN CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------+----------------------------------------------- + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; diff --git a/expected/24_sub_retries.out b/expected/24_sub_retries.out index e94a909..aeef9bc 100644 --- a/expected/24_sub_retries.out +++ b/expected/24_sub_retries.out @@ -164,12 +164,12 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " diff --git a/expected/34_multi.out b/expected/34_multi.out index 91f11f4..2065aa5 100644 --- a/expected/34_multi.out +++ b/expected/34_multi.out @@ -60,14 +60,14 @@ WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled WARNING: Unhandled deployment logged in pgl_ddl_deploy.unhandled COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------+----------------------------------------------- + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; diff --git a/expected/34_multi_1.out b/expected/34_multi_1.out index e58b38b..a9254db 100644 --- a/expected/34_multi_1.out +++ b/expected/34_multi_1.out @@ -68,14 +68,14 @@ BEGIN CREATE TABLE COMMIT SELECT set_name, ddl_sql_raw, ddl_sql_sent FROM pgl_ddl_deploy.events ORDER BY id DESC LIMIT 10; - set_name | ddl_sql_raw | ddl_sql_sent -----------+-------------------------------------------------------------+------------------------------------------------ - test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); - test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); - test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + set_name | ddl_sql_raw | ddl_sql_sent +----------+-------------------------------------------------------------+----------------------------------------------- + test7 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test5 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foobar.foo(id int primary key); COMMIT; | CREATE TABLE foobar.foo (id int PRIMARY KEY); + test3 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); + test1 | BEGIN; CREATE TABLE foo(id int primary key); COMMIT; | CREATE TABLE foo (id int PRIMARY KEY); test8 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test7 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; test6 | CREATE SCHEMA foobar; | CREATE SCHEMA foobar; diff --git a/expected/52_sub_retries.out b/expected/52_sub_retries.out index 934e93e..8f002a5 100644 --- a/expected/52_sub_retries.out +++ b/expected/52_sub_retries.out @@ -164,12 +164,12 @@ SELECT pubnames, message_type, regexp_replace(regexp_replace(regexp_replace(mess {test6} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test6'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE SCHEMA foobar;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 6,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test8} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test8'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE SCHEMA foobar;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE SCHEMA foobar;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 8,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY); $PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " - {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY); $pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY); \n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'public',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test5} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test5'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$CREATE TABLE foobar.foo (id int PRIMARY KEY);$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 5,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " + {test7} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test7'],\n p_nspname := 'foobar',\n p_relname := 'foo_pkey',\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$CREATE TABLE foobar.foo (id int PRIMARY KEY);$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n CREATE TABLE foobar.foo (id int PRIMARY KEY);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 7,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test1} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test1'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 1,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test2} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test2'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n SELECT pgl_ddl_deploy.lock_safe_executor($PGL_DDL_DEPLOY$DROP TABLE foo CASCADE;$PGL_DDL_DEPLOY$);\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 2,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " {test3} | Q | "\n SELECT pgl_ddl_deploy.subscriber_command\n (\n p_provider_name := ?,\n p_set_name := ARRAY['test3'],\n p_nspname := NULL,\n p_relname := NULL,\n p_ddl_sql_sent := $pgl_ddl_deploy_sql$DROP TABLE foo CASCADE;$pgl_ddl_deploy_sql$,\n p_full_ddl := $pgl_ddl_deploy_sql$\n --Be sure to use provider's search_path for SQL environment consistency\n SET SEARCH_PATH TO \"$user\", public;\n\n DROP TABLE foo CASCADE;\n ;\n $pgl_ddl_deploy_sql$,\n p_pid := ?,\n p_set_config_id := 3,\n p_queue_subscriber_failures := false,\n p_signal_blocking_subscriber_sessions := NULL,\n p_lock_timeout := 3000,\n p_driver := ?\n );\n " diff --git a/src/pgl_ddl_deploy.c b/src/pgl_ddl_deploy.c index 72c7e4b..6e162f7 100644 --- a/src/pgl_ddl_deploy.c +++ b/src/pgl_ddl_deploy.c @@ -98,6 +98,7 @@ rewrite_transaction_safe(PG_FUNCTION_ARGS) ListCell *parsetree_item; StringInfoData str; text *result; + bool isFirst = true; initStringInfo(&str); /* @@ -126,12 +127,16 @@ rewrite_transaction_safe(PG_FUNCTION_ARGS) dropStmt->concurrent = false; } if(shouldEmit) { - deparseRawStmt(&str, parsetree); - appendStringInfoChar(&str, ';'); - if(foreach_current_index(parsetree_item) < list_length(parsetree_list) - 1) + if(!isFirst) { appendStringInfoChar(&str, ' '); } + else + { + isFirst = false; + } + deparseRawStmt(&str, parsetree); + appendStringInfoChar(&str, ';'); } } result = cstring_to_text(str.data); diff --git a/src/postgres_deparse.11.c b/src/postgres_deparse.11.c index 6a97adc..327264b 100644 --- a/src/postgres_deparse.11.c +++ b/src/postgres_deparse.11.c @@ -1,5 +1,7 @@ #include "pg_config.h" -#if(PG_MAJORVERSION_NUM == 11) +#if(PG_VERSION_NUM >= 110000 && PG_VERSION_NUM < 120000) + +// Adapted from https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/13-2.2.0/src/pg_query_deparse.c // Copyright (c) 2015, Lukas Fittl // All rights reserved. @@ -31,5 +33,9855 @@ // POSSIBILITY OF SUCH DAMAGE. #include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "lib/stringinfo.h" +#include "limits.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + const ScanKeyword *keyword = ScanKeywordLookup(val, ScanKeywords, NumScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && keyword != NULL && keyword->category != UNRESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context); + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach(lc, parts) + { + if(idx < 1) { + idx++; + continue; + } + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach (lc, parts) + { + if (lnext(lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (idx < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + idx++; + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach(lc, indirection) + { + if(idx < N) { + idx++; + continue; + } + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, Value *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->val.ival); + break; + case T_Float: + appendStringInfoString(str, value->val.str); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (Value *) lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (Value *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + foreach(lc, object_with_args->objargs) + { + if (IsA(lfirst(lc), TypeName)) + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + else + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + int idx = 0; + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (idx == order_by_pos) + { + if (idx > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (idx > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + idx++; + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, object_with_args->objargs) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (Value *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + int idx = 0; + int idx2 = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (idx != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + idx2 = 0; + for_each_cell(lc2, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (idx2 == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(lc2)) + appendStringInfoString(str, ", "); + idx2++; + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + idx++; + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + case T_FuncCall: + case T_SQLValueFunction: + case T_TypeCast: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_XmlSerialize: + deparseFuncExprWindowless(str, index_elem->expr); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (IsA(stmt->limitCount, A_Const) && IsA(&castNode(A_Const, stmt->limitCount)->val, Null)) + appendStringInfoString(str, "ALL"); + else + deparseCExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + deparseValue(str, &a_const->val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OF: /* IS [NOT] OF - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IS OF "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "IS NOT OF "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + deparseTypeList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + return; + case AEXPR_PAREN: /* nameless dummy node for parentheses */ + // Not present in parse trees when operator_precedence_warning is turned off + Assert(false); + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr)) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + } + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + appendStringInfoString(str, "interval"); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + deparseExpr(str, (Node *) boolean_test->arg); + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, column_def->colname); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + switch (insert_stmt->override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, constraint->conname); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON DELETE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(lc) && castNode(FunctionParameter, lfirst(lnext(lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + // Default + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (Value *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseStringLiteral(str, strVal(linitial(drop_stmt->objects))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "DEPENDS ON EXTENSION "); + deparseColId(str, strVal(alter_object_depends_stmt->extname)); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ProcessedConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_AddOids: /* SET WITH OIDS */ + appendStringInfoString(str, "SET WITH OIDS "); + break; + case AT_AddOidsRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseNodeContext context = DEPARSE_NODE_CONTEXT_NONE; + + appendStringInfoString(str, "ALTER "); + + switch (alter_table_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + context = DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + bool hasAppended = false; + + if (vacuum_stmt->options & VACOPT_VACUUM) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + + if (vacuum_stmt->options & VACOPT_VERBOSE) + + if (vacuum_stmt->options & (~VACOPT_ANALYZE) & (~VACOPT_VACUUM)) + { + appendStringInfoChar(str, '('); + if ((vacuum_stmt->options & VACOPT_ANALYZE) && (vacuum_stmt->options & VACOPT_VACUUM)) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "ANALYZE"); + hasAppended = true; + } + if (vacuum_stmt->options & VACOPT_VERBOSE) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "VERBOSE"); + hasAppended = true; + } + if (vacuum_stmt->options & VACOPT_FREEZE) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "FREEZE"); + hasAppended = true; + } + if (vacuum_stmt->options & VACOPT_FULL) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "FULL"); + hasAppended = true; + } + if (vacuum_stmt->options & VACOPT_SKIPTOAST) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "PROCESS_TOAST false"); + hasAppended = true; + } + if (vacuum_stmt->options & VACOPT_DISABLE_PAGE_SKIPPING) + { + if(hasAppended) + { + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, "DISABLE_PAGE_SKIPPING"); + hasAppended = true; + } + appendStringInfoString(str, ") "); + } + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + if (list_length(explain_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + + foreach(lc, explain_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL && IsA(def_elem->arg, String)) + { + appendStringInfoChar(str, ' '); + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (def_elem->arg != NULL && (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float))) + { + appendStringInfoChar(str, ' '); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "FREEZE"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "HEADER"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, index_stmt->idxname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + if (reindex_stmt->options & REINDEXOPT_VERBOSE) + appendStringInfoString(str, "(VERBOSE) "); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + deparseStringLiteral(str, create_table_space_stmt->location); + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->tables) > 0) + { + appendStringInfoString(str, "FOR TABLE "); + deparseRelationExprList(str, create_publication_stmt->tables); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->tables) > 0) + { + switch (alter_publication_stmt->tableAction) + { + case DEFELEM_SET: + appendStringInfoString(str, "SET TABLE "); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD TABLE "); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP TABLE "); + break; + case DEFELEM_UNSPEC: + Assert(false); + break; + } + + deparseRelationExprList(str, alter_publication_stmt->tables); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (Value *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + deparseExprList(str, create_stats_stmt->exprs); + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "SESSION ALL"); + else + appendStringInfoString(str, variable_show_stmt->name); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (intVal(defelem->arg) == 1) + { + appendStringInfoString(str, " ENABLE "); + } + else if (intVal(defelem->arg) == 0) + { + appendStringInfoString(str, " DISABLE "); + } + else + { + Assert(false); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (Value *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + if (strcmp(strVal(&castNode(A_Const, castNode(TypeCast, lsecond(xml_expr->args))->arg)->val), "t") == 0) + appendStringInfoString(str, " PRESERVE WHITESPACE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (nodeTag(&castNode(A_Const, lsecond(xml_expr->args))->val) == T_Null) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context) +{ + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->val.str)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->val.str); + } else { + appendStringInfoString(str, value->val.str); + } + break; + case T_BitString: + if (strlen(value->val.str) >= 1 && value->val.str[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->val.str + 1); + } + else if (strlen(value->val.str) >= 1 && value->val.str[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->val.str + 1); + } + else + { + Assert(false); + } + break; + case T_Null: + appendStringInfoString(str, "NULL"); + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} -#endif \ No newline at end of file +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif diff --git a/src/postgres_deparse.12.c b/src/postgres_deparse.12.c index 4f86901..1653b52 100644 --- a/src/postgres_deparse.12.c +++ b/src/postgres_deparse.12.c @@ -1,5 +1,7 @@ #include "pg_config.h" -#if(PG_MAJORVERSION_NUM == 12) +#if(PG_VERSION_NUM >= 120000 && PG_VERSION_NUM < 130000) + +// Adapted from https://raw.githubusercontent.com/pganalyze/libpg_query/refs/tags/13-2.2.0/src/pg_query_deparse.c // Copyright (c) 2015, Lukas Fittl // All rights reserved. @@ -31,5 +33,9864 @@ // POSSIBILITY OF SUCH DAMAGE. #include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "limits.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context); + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach(lc, parts) + { + if(idx < 1) { + idx++; + continue; + } + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach (lc, parts) + { + if (lnext(lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (idx < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + idx++; + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + int idx = 0; + + foreach(lc, indirection) + { + if(idx < N) { + idx++; + continue; + } + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, Value *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->val.ival); + break; + case T_Float: + appendStringInfoString(str, value->val.str); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (Value *) lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (Value *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (Value *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + foreach(lc, object_with_args->objargs) + { + if (IsA(lfirst(lc), TypeName)) + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + else + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + int idx = 0; + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (idx == order_by_pos) + { + if (idx > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (idx > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + idx++; + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, object_with_args->objargs) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (Value *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + int idx = 0; + int idx2 = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (idx != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + idx2 = 0; + for_each_cell(lc2, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (idx2 == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(lc2)) + appendStringInfoString(str, ", "); + idx2++; + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + idx++; + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + case T_FuncCall: + case T_SQLValueFunction: + case T_TypeCast: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_XmlSerialize: + deparseFuncExprWindowless(str, index_elem->expr); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (IsA(stmt->limitCount, A_Const) && IsA(&castNode(A_Const, stmt->limitCount)->val, Null)) + appendStringInfoString(str, "ALL"); + else + deparseCExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + deparseValue(str, &a_const->val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OF: /* IS [NOT] OF - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IS OF "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "IS NOT OF "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + deparseTypeList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((Value *) linitial(a_expr->name))->val.str; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + return; + case AEXPR_PAREN: /* nameless dummy node for parentheses */ + // Not present in parse trees when operator_precedence_warning is turned off + Assert(false); + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr)) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + } + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + appendStringInfoString(str, "interval"); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + deparseExpr(str, (Node *) boolean_test->arg); + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, column_def->colname); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + switch (insert_stmt->override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, constraint->conname); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON DELETE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(lc) && castNode(FunctionParameter, lfirst(lnext(lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + // Default + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (Value *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseStringLiteral(str, strVal(linitial(drop_stmt->objects))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "DEPENDS ON EXTENSION "); + deparseColId(str, strVal(alter_object_depends_stmt->extname)); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ProcessedConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + DeparseNodeContext context = DEPARSE_NODE_CONTEXT_NONE; + + appendStringInfoString(str, "ALTER "); + + switch (alter_table_stmt->relkind) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + context = DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + if (list_length(vacuum_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, vacuum_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (Value *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + if (list_length(explain_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + + foreach(lc, explain_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL && IsA(def_elem->arg, String)) + { + appendStringInfoChar(str, ' '); + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (def_elem->arg != NULL && (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float))) + { + appendStringInfoChar(str, ' '); + deparseNumericOnly(str, (Value *) def_elem->arg); + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "FREEZE"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0 && (def_elem->arg == NULL || intVal(def_elem->arg) == 1)) + { + appendStringInfoString(str, "HEADER"); + if (def_elem->arg != NULL && intVal(def_elem->arg) == 1) + appendStringInfoString(str, " 1"); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (Value *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, index_stmt->idxname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 1) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && intVal(def_elem->arg) == 0) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + if (reindex_stmt->options & REINDEXOPT_VERBOSE) + appendStringInfoString(str, "(VERBOSE) "); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + deparseStringLiteral(str, create_table_space_stmt->location); + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->tables) > 0) + { + appendStringInfoString(str, "FOR TABLE "); + deparseRelationExprList(str, create_publication_stmt->tables); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->tables) > 0) + { + switch (alter_publication_stmt->tableAction) + { + case DEFELEM_SET: + appendStringInfoString(str, "SET TABLE "); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD TABLE "); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP TABLE "); + break; + case DEFELEM_UNSPEC: + Assert(false); + break; + } + + deparseRelationExprList(str, alter_publication_stmt->tables); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (Value *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + deparseExprList(str, create_stats_stmt->exprs); + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "SESSION ALL"); + else + appendStringInfoString(str, variable_show_stmt->name); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (intVal(defelem->arg) == 1) + { + appendStringInfoString(str, " ENABLE "); + } + else if (intVal(defelem->arg) == 0) + { + appendStringInfoString(str, " DISABLE "); + } + else + { + Assert(false); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (Value *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + if (strcmp(strVal(&castNode(A_Const, castNode(TypeCast, lsecond(xml_expr->args))->arg)->val), "t") == 0) + appendStringInfoString(str, " PRESERVE WHITESPACE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (nodeTag(&castNode(A_Const, lsecond(xml_expr->args))->val) == T_Null) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + if (cluster_stmt->options & CLUOPT_VERBOSE) + appendStringInfoString(str, "VERBOSE "); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, Value *value, DeparseNodeContext context) +{ + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->val.str)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->val.str); + } else { + appendStringInfoString(str, value->val.str); + } + break; + case T_BitString: + if (strlen(value->val.str) >= 1 && value->val.str[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->val.str + 1); + } + else if (strlen(value->val.str) >= 1 && value->val.str[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->val.str + 1); + } + else + { + Assert(false); + } + break; + case T_Null: + appendStringInfoString(str, "NULL"); + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} -#endif \ No newline at end of file +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} +#endif From 20e4e1ecb331291f6306d56426e1f45473bd4203 Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 12:20:43 -0500 Subject: [PATCH 6/7] Fix deb build --- Makefile | 18 +++++++++--------- src/pgl_ddl_deploy.c => pgl_ddl_deploy.c | 0 ...tgres_deparse.11.c => postgres_deparse.11.c | 0 ...tgres_deparse.12.c => postgres_deparse.12.c | 0 ...tgres_deparse.13.c => postgres_deparse.13.c | 0 ...tgres_deparse.14.c => postgres_deparse.14.c | 0 ...tgres_deparse.15.c => postgres_deparse.15.c | 0 ...tgres_deparse.16.c => postgres_deparse.16.c | 0 ...tgres_deparse.17.c => postgres_deparse.17.c | 0 ...tgres_deparse.18.c => postgres_deparse.18.c | 0 src/postgres_deparse.h => postgres_deparse.h | 0 11 files changed, 9 insertions(+), 9 deletions(-) rename src/pgl_ddl_deploy.c => pgl_ddl_deploy.c (100%) rename src/postgres_deparse.11.c => postgres_deparse.11.c (100%) rename src/postgres_deparse.12.c => postgres_deparse.12.c (100%) rename src/postgres_deparse.13.c => postgres_deparse.13.c (100%) rename src/postgres_deparse.14.c => postgres_deparse.14.c (100%) rename src/postgres_deparse.15.c => postgres_deparse.15.c (100%) rename src/postgres_deparse.16.c => postgres_deparse.16.c (100%) rename src/postgres_deparse.17.c => postgres_deparse.17.c (100%) rename src/postgres_deparse.18.c => postgres_deparse.18.c (100%) rename src/postgres_deparse.h => postgres_deparse.h (100%) diff --git a/Makefile b/Makefile index 9e1ab02..5b3ebd2 100644 --- a/Makefile +++ b/Makefile @@ -14,15 +14,15 @@ DATA = pgl_ddl_deploy--1.0.sql pgl_ddl_deploy--1.0--1.1.sql \ pgl_ddl_deploy--2.4.sql MODULES = ddl_deparse MODULE_big = pgl_ddl_deploy -OBJS = src/postgres_deparse.11.o \ - src/postgres_deparse.12.o \ - src/postgres_deparse.13.o \ - src/postgres_deparse.14.o \ - src/postgres_deparse.15.o \ - src/postgres_deparse.16.o \ - src/postgres_deparse.17.o \ - src/postgres_deparse.18.o \ - src/pgl_ddl_deploy.o +OBJS = postgres_deparse.11.o \ + postgres_deparse.12.o \ + postgres_deparse.13.o \ + postgres_deparse.14.o \ + postgres_deparse.15.o \ + postgres_deparse.16.o \ + postgres_deparse.17.o \ + postgres_deparse.18.o \ + pgl_ddl_deploy.o REGRESS := 01_create_ext 02_setup 03_add_configs 04_deploy 04_deploy_update \ 05_allowed 06_multi 07_edges 08_ignored \ diff --git a/src/pgl_ddl_deploy.c b/pgl_ddl_deploy.c similarity index 100% rename from src/pgl_ddl_deploy.c rename to pgl_ddl_deploy.c diff --git a/src/postgres_deparse.11.c b/postgres_deparse.11.c similarity index 100% rename from src/postgres_deparse.11.c rename to postgres_deparse.11.c diff --git a/src/postgres_deparse.12.c b/postgres_deparse.12.c similarity index 100% rename from src/postgres_deparse.12.c rename to postgres_deparse.12.c diff --git a/src/postgres_deparse.13.c b/postgres_deparse.13.c similarity index 100% rename from src/postgres_deparse.13.c rename to postgres_deparse.13.c diff --git a/src/postgres_deparse.14.c b/postgres_deparse.14.c similarity index 100% rename from src/postgres_deparse.14.c rename to postgres_deparse.14.c diff --git a/src/postgres_deparse.15.c b/postgres_deparse.15.c similarity index 100% rename from src/postgres_deparse.15.c rename to postgres_deparse.15.c diff --git a/src/postgres_deparse.16.c b/postgres_deparse.16.c similarity index 100% rename from src/postgres_deparse.16.c rename to postgres_deparse.16.c diff --git a/src/postgres_deparse.17.c b/postgres_deparse.17.c similarity index 100% rename from src/postgres_deparse.17.c rename to postgres_deparse.17.c diff --git a/src/postgres_deparse.18.c b/postgres_deparse.18.c similarity index 100% rename from src/postgres_deparse.18.c rename to postgres_deparse.18.c diff --git a/src/postgres_deparse.h b/postgres_deparse.h similarity index 100% rename from src/postgres_deparse.h rename to postgres_deparse.h From a4e4be77ac36c10e918045d8e73757041d71057b Mon Sep 17 00:00:00 2001 From: Jacob Burroughs Date: Wed, 17 Jun 2026 13:12:39 -0500 Subject: [PATCH 7/7] Update debian changelog --- debian/changelog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 063f30a..c86b9f6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +pgl-ddl-deploy (2.4.0-1) unstable; urgency=medium + + * Support for replicating index DDL + * Prevent DDL that internally touches toast tables from being silently dropped + + -- Jacob Burroughs Wed, 17 Jun 2026 13:12:22 -0500 + pgl-ddl-deploy (2.3.0-1) unstable; urgency=medium * Support for Postgres 16