From 48055b3b43ad07d774a36bd531d29d7f24f07986 Mon Sep 17 00:00:00 2001 From: Henson Choi Date: Fri, 30 Oct 2026 21:13:37 +0900 Subject: [PATCH v1 1/2] Add tests for column dependencies of MERGE actions A SQL-standard function body, or a rule action with a MERGE in WITH, does not depend on the target columns of the MERGE actions, so ALTER COLUMN TYPE and DROP COLUMN on those columns succeed and the stored query is left referring to dropped columns. The expected output shows the current behavior; the next commit fixes it. --- .../regress/expected/create_function_sql.out | 35 ++++++++++++++++++ src/test/regress/expected/rules.out | 36 +++++++++++++++++++ src/test/regress/sql/create_function_sql.sql | 21 +++++++++++ src/test/regress/sql/rules.sql | 19 ++++++++++ 4 files changed, 111 insertions(+) diff --git a/src/test/regress/expected/create_function_sql.out b/src/test/regress/expected/create_function_sql.out index 42524230d2b..83bb12ac40a 100644 --- a/src/test/regress/expected/create_function_sql.out +++ b/src/test/regress/expected/create_function_sql.out @@ -465,6 +465,41 @@ DETAIL: It depends on temporary sequence mytempseq. -- This discards mytempseq and therefore functest_tempseq(). If it fails to, -- the function will appear in the information_schema tests below. DISCARD TEMP; +-- Check dependencies on the target columns of MERGE actions within +-- SQL-standard body, like those of INSERT and UPDATE +CREATE TABLE functest_mtgt (k int, a int, b int, c int); +CREATE TABLE functest_msrc (k int, v int); +CREATE FUNCTION functest_merge() RETURNS void + BEGIN ATOMIC + MERGE INTO functest_mtgt t USING functest_msrc s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET a = s.v + WHEN NOT MATCHED THEN INSERT (k, b) VALUES (s.k, s.v); + END; +ALTER TABLE functest_mtgt ALTER COLUMN a TYPE bigint; +ALTER TABLE functest_mtgt DROP COLUMN a; +ALTER TABLE functest_mtgt DROP COLUMN b; +ALTER TABLE functest_mtgt DROP COLUMN c; -- not assigned, so OK +SELECT pg_get_functiondef('functest_merge'::regproc); + pg_get_functiondef +------------------------------------------------------------ + CREATE OR REPLACE FUNCTION temp_func_test.functest_merge()+ + RETURNS void + + LANGUAGE sql + + BEGIN ATOMIC + + MERGE INTO functest_mtgt AS t + + USING functest_msrc s + + ON (t.k = s.k) + + WHEN MATCHED + + THEN UPDATE SET "........pg.dropped.2........" = s.v + + WHEN NOT MATCHED + + THEN INSERT (k, "........pg.dropped.3........") + + VALUES (s.k, s.v); + + END + + +(1 row) + +DROP FUNCTION functest_merge(); +DROP TABLE functest_mtgt, functest_msrc; -- information_schema tests CREATE FUNCTION functest_IS_1(a int, b int default 1, c text default 'foo') RETURNS int diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 38c9b04f72c..0b687a5e5b3 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -4075,6 +4075,42 @@ END DROP FUNCTION merge_sf_test; DROP FUNCTION merge_sf_test2; DROP TABLE sf_target; +-- Check dependencies of rule actions on the target columns of MERGE actions +-- in WITH +CREATE TABLE rule_merge_tgt (k int, a int, b int, c int); +CREATE TABLE rule_merge_src (k int); +CREATE RULE rule_merge_deps AS ON INSERT TO rule_merge_src + DO ALSO WITH m AS ( + MERGE INTO rule_merge_tgt t USING rule_merge_src s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET a = 0 + WHEN NOT MATCHED THEN INSERT (k, b) VALUES (s.k, 0) + RETURNING t.k) + SELECT count(*) FROM m; +ALTER TABLE rule_merge_tgt ALTER COLUMN a TYPE bigint; +ALTER TABLE rule_merge_tgt DROP COLUMN a; +ALTER TABLE rule_merge_tgt DROP COLUMN b; +ALTER TABLE rule_merge_tgt DROP COLUMN c; -- not assigned, so OK +SELECT pg_get_ruledef(oid, true) FROM pg_rewrite + WHERE rulename = 'rule_merge_deps'; + pg_get_ruledef +---------------------------------------------------------------- + CREATE RULE rule_merge_deps AS + + ON INSERT TO rule_merge_src DO WITH m AS ( + + MERGE INTO rule_merge_tgt AS t + + USING rule_merge_src s + + ON t.k = s.k + + WHEN MATCHED + + THEN UPDATE SET "........pg.dropped.2........" = 0+ + WHEN NOT MATCHED + + THEN INSERT (k, "........pg.dropped.3........") + + VALUES (s.k, 0) + + RETURNING t.k + + ) + + SELECT count(*) AS count + + FROM m; +(1 row) + +DROP TABLE rule_merge_src, rule_merge_tgt; -- -- Test enabling/disabling -- diff --git a/src/test/regress/sql/create_function_sql.sql b/src/test/regress/sql/create_function_sql.sql index 4543273f93a..6d81067b96f 100644 --- a/src/test/regress/sql/create_function_sql.sql +++ b/src/test/regress/sql/create_function_sql.sql @@ -252,6 +252,27 @@ CREATE FUNCTION functest_tempseq() RETURNS int -- the function will appear in the information_schema tests below. DISCARD TEMP; +-- Check dependencies on the target columns of MERGE actions within +-- SQL-standard body, like those of INSERT and UPDATE +CREATE TABLE functest_mtgt (k int, a int, b int, c int); +CREATE TABLE functest_msrc (k int, v int); + +CREATE FUNCTION functest_merge() RETURNS void + BEGIN ATOMIC + MERGE INTO functest_mtgt t USING functest_msrc s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET a = s.v + WHEN NOT MATCHED THEN INSERT (k, b) VALUES (s.k, s.v); + END; + +ALTER TABLE functest_mtgt ALTER COLUMN a TYPE bigint; +ALTER TABLE functest_mtgt DROP COLUMN a; +ALTER TABLE functest_mtgt DROP COLUMN b; +ALTER TABLE functest_mtgt DROP COLUMN c; -- not assigned, so OK +SELECT pg_get_functiondef('functest_merge'::regproc); + +DROP FUNCTION functest_merge(); +DROP TABLE functest_mtgt, functest_msrc; + -- information_schema tests diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql index abe89d097c9..869487b7bcb 100644 --- a/src/test/regress/sql/rules.sql +++ b/src/test/regress/sql/rules.sql @@ -1392,6 +1392,25 @@ DROP FUNCTION merge_sf_test; DROP FUNCTION merge_sf_test2; DROP TABLE sf_target; +-- Check dependencies of rule actions on the target columns of MERGE actions +-- in WITH +CREATE TABLE rule_merge_tgt (k int, a int, b int, c int); +CREATE TABLE rule_merge_src (k int); +CREATE RULE rule_merge_deps AS ON INSERT TO rule_merge_src + DO ALSO WITH m AS ( + MERGE INTO rule_merge_tgt t USING rule_merge_src s ON t.k = s.k + WHEN MATCHED THEN UPDATE SET a = 0 + WHEN NOT MATCHED THEN INSERT (k, b) VALUES (s.k, 0) + RETURNING t.k) + SELECT count(*) FROM m; +ALTER TABLE rule_merge_tgt ALTER COLUMN a TYPE bigint; +ALTER TABLE rule_merge_tgt DROP COLUMN a; +ALTER TABLE rule_merge_tgt DROP COLUMN b; +ALTER TABLE rule_merge_tgt DROP COLUMN c; -- not assigned, so OK +SELECT pg_get_ruledef(oid, true) FROM pg_rewrite + WHERE rulename = 'rule_merge_deps'; +DROP TABLE rule_merge_src, rule_merge_tgt; + -- -- Test enabling/disabling -- -- 2.54.0 (Apple Git-157)