From afbec7faa3b8c86a6ad4ab386a7abe6b43027d9c Mon Sep 17 00:00:00 2001 From: Ekaterina Sokolova Date: Tue, 18 Jun 2024 11:48:15 +0300 Subject: [PATCH 1/7] Update pg_pathman due to vanilla PostgreSQL. 1. Fix regression output due to fd0398fcb099. Changed tests: pathman_only and pathman_rowmarks. 2. Fix code due to commit d20d8fbd3e4d. 3. Fix comments in test files due to alternate outputs. --- expected/pathman_only.out | 26 +- expected/pathman_only_1.out | 26 +- expected/pathman_only_2.out | 26 +- expected/pathman_only_3.out | 26 +- expected/pathman_only_4.out | 299 +++++++++++++++++++++++ expected/pathman_rowmarks.out | 27 ++- expected/pathman_rowmarks_1.out | 27 ++- expected/pathman_rowmarks_2.out | 27 ++- expected/pathman_rowmarks_3.out | 27 ++- expected/pathman_rowmarks_4.out | 407 ++++++++++++++++++++++++++++++++ sql/pathman_only.sql | 26 +- sql/pathman_rowmarks.sql | 27 ++- src/pl_funcs.c | 11 + src/relation_info.c | 3 +- 14 files changed, 939 insertions(+), 46 deletions(-) create mode 100644 expected/pathman_only_4.out create mode 100644 expected/pathman_rowmarks_4.out diff --git a/expected/pathman_only.out b/expected/pathman_only.out index 1b9f6a6b..f44f2256 100644 --- a/expected/pathman_only.out +++ b/expected/pathman_only.out @@ -3,13 +3,31 @@ * NOTE: This test behaves differenly on PgPro * --------------------------------------------- * - * Since 12 (608b167f9f), CTEs which are scanned once are no longer an - * optimization fence, which changes practically all plans here. There is + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is * an option to forcibly make them MATERIALIZED, but we also need to run tests * on older versions, so create pathman_only_1.out instead. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_only_1.out b/expected/pathman_only_1.out index b92a8eaf..ce6fd127 100644 --- a/expected/pathman_only_1.out +++ b/expected/pathman_only_1.out @@ -3,13 +3,31 @@ * NOTE: This test behaves differenly on PgPro * --------------------------------------------- * - * Since 12 (608b167f9f), CTEs which are scanned once are no longer an - * optimization fence, which changes practically all plans here. There is + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is * an option to forcibly make them MATERIALIZED, but we also need to run tests * on older versions, so create pathman_only_1.out instead. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_only_2.out b/expected/pathman_only_2.out index c37dd5f4..6aeadb76 100644 --- a/expected/pathman_only_2.out +++ b/expected/pathman_only_2.out @@ -3,13 +3,31 @@ * NOTE: This test behaves differenly on PgPro * --------------------------------------------- * - * Since 12 (608b167f9f), CTEs which are scanned once are no longer an - * optimization fence, which changes practically all plans here. There is + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is * an option to forcibly make them MATERIALIZED, but we also need to run tests * on older versions, so create pathman_only_1.out instead. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_only_3.out b/expected/pathman_only_3.out index 2f2fcc75..1999309d 100644 --- a/expected/pathman_only_3.out +++ b/expected/pathman_only_3.out @@ -3,13 +3,31 @@ * NOTE: This test behaves differenly on PgPro * --------------------------------------------- * - * Since 12 (608b167f9f), CTEs which are scanned once are no longer an - * optimization fence, which changes practically all plans here. There is + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is * an option to forcibly make them MATERIALIZED, but we also need to run tests * on older versions, so create pathman_only_1.out instead. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_only_4.out b/expected/pathman_only_4.out new file mode 100644 index 00000000..fbcc397c --- /dev/null +++ b/expected/pathman_only_4.out @@ -0,0 +1,299 @@ +/* + * --------------------------------------------- + * NOTE: This test behaves differenly on PgPro + * --------------------------------------------- + * + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is + * an option to forcibly make them MATERIALIZED, but we also need to run tests + * on older versions, so create pathman_only_1.out instead. + * + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. + */ +\set VERBOSITY terse +SET search_path = 'public'; +CREATE EXTENSION pg_pathman; +CREATE SCHEMA test_only; +/* Test special case: ONLY statement with not-ONLY for partitioned table */ +CREATE TABLE test_only.from_only_test(val INT NOT NULL); +INSERT INTO test_only.from_only_test SELECT generate_series(1, 20); +SELECT create_range_partitions('test_only.from_only_test', 'val', 1, 2); + create_range_partitions +------------------------- + 10 +(1 row) + +VACUUM ANALYZE; +/* should be OK */ +EXPLAIN (COSTS OFF) +SELECT * FROM ONLY test_only.from_only_test +UNION SELECT * FROM test_only.from_only_test; + QUERY PLAN +------------------------------------------------------------------- + HashAggregate + Group Key: from_only_test.val + -> Append + -> Seq Scan on from_only_test + -> Append + -> Seq Scan on from_only_test_1 from_only_test_2 + -> Seq Scan on from_only_test_2 from_only_test_3 + -> Seq Scan on from_only_test_3 from_only_test_4 + -> Seq Scan on from_only_test_4 from_only_test_5 + -> Seq Scan on from_only_test_5 from_only_test_6 + -> Seq Scan on from_only_test_6 from_only_test_7 + -> Seq Scan on from_only_test_7 from_only_test_8 + -> Seq Scan on from_only_test_8 from_only_test_9 + -> Seq Scan on from_only_test_9 from_only_test_10 + -> Seq Scan on from_only_test_10 from_only_test_11 +(15 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +SELECT * FROM test_only.from_only_test +UNION SELECT * FROM ONLY test_only.from_only_test; + QUERY PLAN +---------------------------------------------------------- + HashAggregate + Group Key: from_only_test.val + -> Append + -> Append + -> Seq Scan on from_only_test_1 + -> Seq Scan on from_only_test_2 + -> Seq Scan on from_only_test_3 + -> Seq Scan on from_only_test_4 + -> Seq Scan on from_only_test_5 + -> Seq Scan on from_only_test_6 + -> Seq Scan on from_only_test_7 + -> Seq Scan on from_only_test_8 + -> Seq Scan on from_only_test_9 + -> Seq Scan on from_only_test_10 + -> Seq Scan on from_only_test from_only_test_11 +(15 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +SELECT * FROM test_only.from_only_test +UNION SELECT * FROM test_only.from_only_test +UNION SELECT * FROM ONLY test_only.from_only_test; + QUERY PLAN +------------------------------------------------------------------- + HashAggregate + Group Key: from_only_test.val + -> Append + -> Append + -> Seq Scan on from_only_test_1 + -> Seq Scan on from_only_test_2 + -> Seq Scan on from_only_test_3 + -> Seq Scan on from_only_test_4 + -> Seq Scan on from_only_test_5 + -> Seq Scan on from_only_test_6 + -> Seq Scan on from_only_test_7 + -> Seq Scan on from_only_test_8 + -> Seq Scan on from_only_test_9 + -> Seq Scan on from_only_test_10 + -> Append + -> Seq Scan on from_only_test_1 from_only_test_12 + -> Seq Scan on from_only_test_2 from_only_test_13 + -> Seq Scan on from_only_test_3 from_only_test_14 + -> Seq Scan on from_only_test_4 from_only_test_15 + -> Seq Scan on from_only_test_5 from_only_test_16 + -> Seq Scan on from_only_test_6 from_only_test_17 + -> Seq Scan on from_only_test_7 from_only_test_18 + -> Seq Scan on from_only_test_8 from_only_test_19 + -> Seq Scan on from_only_test_9 from_only_test_20 + -> Seq Scan on from_only_test_10 from_only_test_21 + -> Seq Scan on from_only_test from_only_test_22 +(26 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +SELECT * FROM ONLY test_only.from_only_test +UNION SELECT * FROM test_only.from_only_test +UNION SELECT * FROM test_only.from_only_test; + QUERY PLAN +------------------------------------------------------------------- + HashAggregate + Group Key: from_only_test.val + -> Append + -> Seq Scan on from_only_test + -> Append + -> Seq Scan on from_only_test_1 from_only_test_2 + -> Seq Scan on from_only_test_2 from_only_test_3 + -> Seq Scan on from_only_test_3 from_only_test_4 + -> Seq Scan on from_only_test_4 from_only_test_5 + -> Seq Scan on from_only_test_5 from_only_test_6 + -> Seq Scan on from_only_test_6 from_only_test_7 + -> Seq Scan on from_only_test_7 from_only_test_8 + -> Seq Scan on from_only_test_8 from_only_test_9 + -> Seq Scan on from_only_test_9 from_only_test_10 + -> Seq Scan on from_only_test_10 from_only_test_11 + -> Append + -> Seq Scan on from_only_test_1 from_only_test_13 + -> Seq Scan on from_only_test_2 from_only_test_14 + -> Seq Scan on from_only_test_3 from_only_test_15 + -> Seq Scan on from_only_test_4 from_only_test_16 + -> Seq Scan on from_only_test_5 from_only_test_17 + -> Seq Scan on from_only_test_6 from_only_test_18 + -> Seq Scan on from_only_test_7 from_only_test_19 + -> Seq Scan on from_only_test_8 from_only_test_20 + -> Seq Scan on from_only_test_9 from_only_test_21 + -> Seq Scan on from_only_test_10 from_only_test_22 +(26 rows) + +/* not ok, ONLY|non-ONLY in one query (this is not the case for PgPro) */ +EXPLAIN (COSTS OFF) +SELECT * FROM test_only.from_only_test a +JOIN ONLY test_only.from_only_test b USING(val); + QUERY PLAN +--------------------------------------------- + Nested Loop + -> Seq Scan on from_only_test b + -> Custom Scan (RuntimeAppend) + Prune by: (a.val = b.val) + -> Seq Scan on from_only_test_1 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_2 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_3 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_4 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_5 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_6 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_7 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_8 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_9 a + Filter: (b.val = val) + -> Seq Scan on from_only_test_10 a + Filter: (b.val = val) +(24 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +WITH q1 AS (SELECT * FROM test_only.from_only_test), + q2 AS (SELECT * FROM ONLY test_only.from_only_test) +SELECT * FROM q1 JOIN q2 USING(val); + QUERY PLAN +--------------------------------------------------------------- + Nested Loop + -> Seq Scan on from_only_test from_only_test_1 + -> Custom Scan (RuntimeAppend) + Prune by: (from_only_test.val = from_only_test_1.val) + -> Seq Scan on from_only_test_1 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_2 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_3 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_4 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_5 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_6 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_7 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_8 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_9 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_10 from_only_test + Filter: (from_only_test_1.val = val) +(24 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +WITH q1 AS (SELECT * FROM ONLY test_only.from_only_test) +SELECT * FROM test_only.from_only_test JOIN q1 USING(val); + QUERY PLAN +--------------------------------------------------------------- + Nested Loop + -> Seq Scan on from_only_test from_only_test_1 + -> Custom Scan (RuntimeAppend) + Prune by: (from_only_test.val = from_only_test_1.val) + -> Seq Scan on from_only_test_1 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_2 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_3 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_4 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_5 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_6 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_7 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_8 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_9 from_only_test + Filter: (from_only_test_1.val = val) + -> Seq Scan on from_only_test_10 from_only_test + Filter: (from_only_test_1.val = val) +(24 rows) + +/* should be OK */ +EXPLAIN (COSTS OFF) +SELECT * FROM test_only.from_only_test +WHERE val = (SELECT val FROM ONLY test_only.from_only_test + ORDER BY val ASC + LIMIT 1); + QUERY PLAN +----------------------------------------------------------------- + Custom Scan (RuntimeAppend) + Prune by: (from_only_test.val = (InitPlan 1).col1) + InitPlan 1 + -> Limit + -> Sort + Sort Key: from_only_test_1.val + -> Seq Scan on from_only_test from_only_test_1 + -> Seq Scan on from_only_test_1 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_2 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_3 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_4 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_5 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_6 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_7 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_8 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_9 from_only_test + Filter: (val = (InitPlan 1).col1) + -> Seq Scan on from_only_test_10 from_only_test + Filter: (val = (InitPlan 1).col1) +(27 rows) + +DROP TABLE test_only.from_only_test CASCADE; +NOTICE: drop cascades to 11 other objects +DROP SCHEMA test_only; +DROP EXTENSION pg_pathman; diff --git a/expected/pathman_rowmarks.out b/expected/pathman_rowmarks.out index ea047c9e..6d4611ee 100644 --- a/expected/pathman_rowmarks.out +++ b/expected/pathman_rowmarks.out @@ -1,13 +1,30 @@ /* * ------------------------------------------- - * NOTE: This test behaves differenly on 9.5 + * NOTE: This test behaves differenly on PgPro * ------------------------------------------- * - * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, - * causing different output; pathman_rowmarks_2.out is the updated version. + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ SET search_path = 'public'; CREATE EXTENSION pg_pathman; diff --git a/expected/pathman_rowmarks_1.out b/expected/pathman_rowmarks_1.out index 256b8637..063fca8d 100644 --- a/expected/pathman_rowmarks_1.out +++ b/expected/pathman_rowmarks_1.out @@ -1,13 +1,30 @@ /* * ------------------------------------------- - * NOTE: This test behaves differenly on 9.5 + * NOTE: This test behaves differenly on PgPro * ------------------------------------------- * - * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, - * causing different output; pathman_rowmarks_2.out is the updated version. + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ SET search_path = 'public'; CREATE EXTENSION pg_pathman; diff --git a/expected/pathman_rowmarks_2.out b/expected/pathman_rowmarks_2.out index 06fb88ac..91d7804e 100644 --- a/expected/pathman_rowmarks_2.out +++ b/expected/pathman_rowmarks_2.out @@ -1,13 +1,30 @@ /* * ------------------------------------------- - * NOTE: This test behaves differenly on 9.5 + * NOTE: This test behaves differenly on PgPro * ------------------------------------------- * - * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, - * causing different output; pathman_rowmarks_2.out is the updated version. + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ SET search_path = 'public'; CREATE EXTENSION pg_pathman; diff --git a/expected/pathman_rowmarks_3.out b/expected/pathman_rowmarks_3.out index af61e5f7..e8644292 100644 --- a/expected/pathman_rowmarks_3.out +++ b/expected/pathman_rowmarks_3.out @@ -1,13 +1,30 @@ /* * ------------------------------------------- - * NOTE: This test behaves differenly on 9.5 + * NOTE: This test behaves differenly on PgPro * ------------------------------------------- * - * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, - * causing different output; pathman_rowmarks_2.out is the updated version. + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ SET search_path = 'public'; CREATE EXTENSION pg_pathman; diff --git a/expected/pathman_rowmarks_4.out b/expected/pathman_rowmarks_4.out new file mode 100644 index 00000000..5fbec84d --- /dev/null +++ b/expected/pathman_rowmarks_4.out @@ -0,0 +1,407 @@ +/* + * ------------------------------------------- + * NOTE: This test behaves differenly on PgPro + * ------------------------------------------- + * + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. + * + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. + */ +SET search_path = 'public'; +CREATE EXTENSION pg_pathman; +CREATE SCHEMA rowmarks; +CREATE TABLE rowmarks.first(id int NOT NULL); +CREATE TABLE rowmarks.second(id int NOT NULL); +INSERT INTO rowmarks.first SELECT generate_series(1, 10); +INSERT INTO rowmarks.second SELECT generate_series(1, 10); +SELECT create_hash_partitions('rowmarks.first', 'id', 5); + create_hash_partitions +------------------------ + 5 +(1 row) + +VACUUM ANALYZE; +/* Not partitioned */ +SELECT * FROM rowmarks.second ORDER BY id FOR UPDATE; + id +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +/* Simple case (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; + QUERY PLAN +----------------------------------------------- + LockRows + -> Sort + Sort Key: first.id + -> Append + -> Seq Scan on first_0 first_1 + -> Seq Scan on first_1 first_2 + -> Seq Scan on first_2 first_3 + -> Seq Scan on first_3 first_4 + -> Seq Scan on first_4 first_5 +(9 rows) + +/* Simple case (execution) */ +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; + id +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +SELECT FROM rowmarks.first ORDER BY id FOR UPDATE; +-- +(10 rows) + +SELECT tableoid > 0 FROM rowmarks.first ORDER BY id FOR UPDATE; + ?column? +---------- + t + t + t + t + t + t + t + t + t + t +(10 rows) + +/* A little harder (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 10 LIMIT 1 + FOR UPDATE) +FOR SHARE; + QUERY PLAN +------------------------------------------------------------- + LockRows + InitPlan 1 + -> Limit + -> LockRows + -> Sort + Sort Key: first_1.id + -> Append + -> Seq Scan on first_0 first_2 + -> Seq Scan on first_1 first_3 + -> Seq Scan on first_2 first_4 + -> Seq Scan on first_3 first_5 + -> Seq Scan on first_4 first_6 + -> Custom Scan (RuntimeAppend) + Prune by: (first.id = (InitPlan 1).col1) + -> Seq Scan on first_0 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_1 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_2 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_3 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_4 first + Filter: (id = (InitPlan 1).col1) +(24 rows) + +/* A little harder (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + id +---- + 6 +(1 row) + +/* Two tables (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + QUERY PLAN +-------------------------------------------------- + LockRows + InitPlan 1 + -> Limit + -> LockRows + -> Sort + Sort Key: second.id + -> Seq Scan on second + -> Custom Scan (RuntimeAppend) + Prune by: (first.id = (InitPlan 1).col1) + -> Seq Scan on first_0 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_1 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_2 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_3 first + Filter: (id = (InitPlan 1).col1) + -> Seq Scan on first_4 first + Filter: (id = (InitPlan 1).col1) +(19 rows) + +/* Two tables (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + id +---- + 6 +(1 row) + +/* JOIN (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +JOIN rowmarks.second USING(id) +ORDER BY id +FOR UPDATE; + QUERY PLAN +----------------------------------------------------- + LockRows + -> Sort + Sort Key: first.id + -> Hash Join + Hash Cond: (first.id = second.id) + -> Append + -> Seq Scan on first_0 first_1 + -> Seq Scan on first_1 first_2 + -> Seq Scan on first_2 first_3 + -> Seq Scan on first_3 first_4 + -> Seq Scan on first_4 first_5 + -> Hash + -> Seq Scan on second +(13 rows) + +/* JOIN (execution) */ +SELECT * FROM rowmarks.first +JOIN rowmarks.second USING(id) +ORDER BY id +FOR UPDATE; + id +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +/* ONLY (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM ONLY rowmarks.first FOR SHARE; + QUERY PLAN +------------------------- + LockRows + -> Seq Scan on first +(2 rows) + +/* ONLY (execution) */ +SELECT * FROM ONLY rowmarks.first FOR SHARE; + id +---- +(0 rows) + +/* Check updates (plan) */ +SET enable_hashjoin = f; /* Hash Semi Join on 10 vs Hash Join on 9.6 */ +SET enable_mergejoin = f; /* Merge Semi Join on 10 vs Merge Join on 9.6 */ +EXPLAIN (COSTS OFF) +UPDATE rowmarks.second SET id = 2 +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1); + QUERY PLAN +--------------------------------------- + Update on second + -> Nested Loop Semi Join + -> Seq Scan on second + Filter: (id = 1) + -> Seq Scan on first_0 first + Filter: (id = 1) +(6 rows) + +EXPLAIN (COSTS OFF) +UPDATE rowmarks.second SET id = 2 +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1); + QUERY PLAN +----------------------------------------------------- + Update on second + -> Nested Loop Semi Join + Join Filter: (second.id = first.id) + -> Seq Scan on second + -> Materialize + -> Append + -> Seq Scan on first_0 first_1 + Filter: (id < 1) + -> Seq Scan on first_1 first_2 + Filter: (id < 1) + -> Seq Scan on first_2 first_3 + Filter: (id < 1) + -> Seq Scan on first_3 first_4 + Filter: (id < 1) + -> Seq Scan on first_4 first_5 + Filter: (id < 1) +(16 rows) + +EXPLAIN (COSTS OFF) +UPDATE rowmarks.second SET id = 2 +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2); + QUERY PLAN +----------------------------------------------------- + Update on second + -> Nested Loop Semi Join + Join Filter: (second.id = first.id) + -> Seq Scan on second + -> Materialize + -> Append + -> Seq Scan on first_0 first_1 + Filter: (id = 1) + -> Seq Scan on first_1 first_2 + Filter: (id = 2) +(10 rows) + +EXPLAIN (COSTS OFF) +UPDATE rowmarks.second SET id = 2 +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1) +RETURNING *, tableoid::regclass; + QUERY PLAN +--------------------------------------- + Update on second + -> Nested Loop Semi Join + -> Seq Scan on second + Filter: (id = 1) + -> Seq Scan on first_0 first + Filter: (id = 1) +(6 rows) + +SET enable_hashjoin = t; +SET enable_mergejoin = t; +/* Check updates (execution) */ +UPDATE rowmarks.second SET id = 1 +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2) +RETURNING *, tableoid::regclass; + id | tableoid +----+----------------- + 1 | rowmarks.second + 1 | rowmarks.second +(2 rows) + +/* Check deletes (plan) */ +SET enable_hashjoin = f; /* Hash Semi Join on 10 vs Hash Join on 9.6 */ +SET enable_mergejoin = f; /* Merge Semi Join on 10 vs Merge Join on 9.6 */ +EXPLAIN (COSTS OFF) +DELETE FROM rowmarks.second +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1); + QUERY PLAN +--------------------------------------- + Delete on second + -> Nested Loop Semi Join + -> Seq Scan on second + Filter: (id = 1) + -> Seq Scan on first_0 first + Filter: (id = 1) +(6 rows) + +EXPLAIN (COSTS OFF) +DELETE FROM rowmarks.second +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id < 1); + QUERY PLAN +----------------------------------------------------- + Delete on second + -> Nested Loop Semi Join + Join Filter: (second.id = first.id) + -> Seq Scan on second + -> Materialize + -> Append + -> Seq Scan on first_0 first_1 + Filter: (id < 1) + -> Seq Scan on first_1 first_2 + Filter: (id < 1) + -> Seq Scan on first_2 first_3 + Filter: (id < 1) + -> Seq Scan on first_3 first_4 + Filter: (id < 1) + -> Seq Scan on first_4 first_5 + Filter: (id < 1) +(16 rows) + +EXPLAIN (COSTS OFF) +DELETE FROM rowmarks.second +WHERE rowmarks.second.id IN (SELECT id FROM rowmarks.first WHERE id = 1 OR id = 2); + QUERY PLAN +----------------------------------------------------- + Delete on second + -> Nested Loop Semi Join + Join Filter: (second.id = first.id) + -> Seq Scan on second + -> Materialize + -> Append + -> Seq Scan on first_0 first_1 + Filter: (id = 1) + -> Seq Scan on first_1 first_2 + Filter: (id = 2) +(10 rows) + +SET enable_hashjoin = t; +SET enable_mergejoin = t; +DROP TABLE rowmarks.first CASCADE; +NOTICE: drop cascades to 5 other objects +DETAIL: drop cascades to table rowmarks.first_0 +drop cascades to table rowmarks.first_1 +drop cascades to table rowmarks.first_2 +drop cascades to table rowmarks.first_3 +drop cascades to table rowmarks.first_4 +DROP TABLE rowmarks.second CASCADE; +DROP SCHEMA rowmarks; +DROP EXTENSION pg_pathman; diff --git a/sql/pathman_only.sql b/sql/pathman_only.sql index 88f4e88a..68dc4ca1 100644 --- a/sql/pathman_only.sql +++ b/sql/pathman_only.sql @@ -3,13 +3,31 @@ * NOTE: This test behaves differenly on PgPro * --------------------------------------------- * - * Since 12 (608b167f9f), CTEs which are scanned once are no longer an - * optimization fence, which changes practically all plans here. There is + * -------------------- + * pathman_only_1.sql + * -------------------- + * Since 608b167f9f in PostgreSQL 12, CTEs which are scanned once are no longer + * an optimization fence, which changes practically all plans here. There is * an option to forcibly make them MATERIALIZED, but we also need to run tests * on older versions, so create pathman_only_1.out instead. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * -------------------- + * pathman_only_2.sql + * -------------------- + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13, output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * -------------------- + * pathman_only_3.sql + * -------------------- + * Since a5fc46414de in PostgreSQL 16, the order of the operands was changed, + * which affected the output of the "Prune by" in EXPLAIN. + * + * -------------------- + * pathman_only_4.sql + * -------------------- + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ \set VERBOSITY terse diff --git a/sql/pathman_rowmarks.sql b/sql/pathman_rowmarks.sql index bb7719ea..8847b80c 100644 --- a/sql/pathman_rowmarks.sql +++ b/sql/pathman_rowmarks.sql @@ -1,13 +1,30 @@ /* * ------------------------------------------- - * NOTE: This test behaves differenly on 9.5 + * NOTE: This test behaves differenly on PgPro * ------------------------------------------- * - * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, - * causing different output; pathman_rowmarks_2.out is the updated version. + * ------------------------ + * pathman_rowmarks_1.sql + * ------------------------ + * Since PostgreSQL 9.5, output of EXPLAIN was changed. * - * Since 55a1954da16 and 6ef77cf46e8 (>= 13) output of EXPLAIN was changed, - * now it includes aliases for inherited tables. + * ------------------------ + * pathman_rowmarks_2.sql + * ------------------------ + * Since 8edd0e794 in PostgreSQL 12, append nodes with single subplan are + * eliminated, causing different output. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since 55a1954da16 and 6ef77cf46e8 in PostgreSQL 13 output of EXPLAIN was + * changed, now it includes aliases for inherited tables. + * + * ------------------------ + * pathman_rowmarks_3.sql + * ------------------------ + * Since fd0398fcb09 in PostgreSQL 17, output of EXPLAIN was + * changed, now it displays SubPlan nodes and output parameters. */ SET search_path = 'public'; CREATE EXTENSION pg_pathman; diff --git a/src/pl_funcs.c b/src/pl_funcs.c index 10538bea..75c1c12a 100644 --- a/src/pl_funcs.c +++ b/src/pl_funcs.c @@ -174,7 +174,12 @@ get_partition_cooked_key_pl(PG_FUNCTION_ARGS) expr_cstr = TextDatumGetCString(values[Anum_pathman_config_expr - 1]); expr = cook_partitioning_expression(relid, expr_cstr, NULL); + +#if PG_VERSION_NUM >= 170000 /* for commit d20d8fbd3e4d */ + cooked_cstr = nodeToStringWithLocations(expr); +#else cooked_cstr = nodeToString(expr); +#endif pfree(expr_cstr); pfree(expr); @@ -196,7 +201,13 @@ get_cached_partition_cooked_key_pl(PG_FUNCTION_ARGS) prel = get_pathman_relation_info(relid); shout_if_prel_is_invalid(relid, prel, PT_ANY); + +#if PG_VERSION_NUM >= 170000 /* for commit d20d8fbd3e4d */ + res = CStringGetTextDatum(nodeToStringWithLocations(prel->expr)); +#else res = CStringGetTextDatum(nodeToString(prel->expr)); +#endif + close_pathman_relation_info(prel); PG_RETURN_DATUM(res); diff --git a/src/relation_info.c b/src/relation_info.c index db75646f..2794a183 100644 --- a/src/relation_info.c +++ b/src/relation_info.c @@ -1491,7 +1491,8 @@ parse_partitioning_expression(const Oid relid, return ((ResTarget *) linitial(select_stmt->targetList))->val; } -/* Parse partitioning expression and return its type and nodeToString() as TEXT */ +/* Parse partitioning expression and return its type and nodeToString() + * (or nodeToStringWithLocations() in version 17 and higher) as TEXT */ Node * cook_partitioning_expression(const Oid relid, const char *expr_cstr, From a0025f4130261a200d2165db1809c022d570d05c Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Tue, 6 Aug 2024 10:24:00 +0300 Subject: [PATCH 2/7] PGPRO-10100: Revert "PGPRO-9797: Temporary disable test pathman_upd_del.sql" This reverts commit 5376dfba1b459de1935982964b2ba94a03fdcd6b. --- Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Makefile b/Makefile index f32398da..f6780044 100644 --- a/Makefile +++ b/Makefile @@ -64,8 +64,6 @@ REGRESS = pathman_array_qual \ pathman_utility_stmt \ pathman_views \ pathman_CVE-2020-14350 - -REGRESS := $(filter-out pathman_upd_del, $(REGRESS)) endif ISOLATION = insert_nodes for_update rollback_on_create_partitions From 810d906815269135838a924942195d9470d3f2e6 Mon Sep 17 00:00:00 2001 From: Marina Polyakova Date: Fri, 1 Nov 2024 19:51:47 +0300 Subject: [PATCH 3/7] PGPRO-10245: fix pathman_upd_del test --- expected/pathman_upd_del.out | 3 + expected/pathman_upd_del_1.out | 3 + expected/pathman_upd_del_2.out | 3 + expected/pathman_upd_del_3.out | 3 + expected/pathman_upd_del_4.out | 464 +++++++++++++++++++++++++++++++++ sql/pathman_upd_del.sql | 3 + 6 files changed, 479 insertions(+) create mode 100644 expected/pathman_upd_del_4.out diff --git a/expected/pathman_upd_del.out b/expected/pathman_upd_del.out index 44bb34fc..752cff27 100644 --- a/expected/pathman_upd_del.out +++ b/expected/pathman_upd_del.out @@ -9,6 +9,9 @@ * plans here. There is an option to forcibly make them MATERIALIZED, but we * also need to run tests on older versions, so put updated plans in * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_upd_del_1.out b/expected/pathman_upd_del_1.out index 0a7e91e9..6e0f312d 100644 --- a/expected/pathman_upd_del_1.out +++ b/expected/pathman_upd_del_1.out @@ -9,6 +9,9 @@ * plans here. There is an option to forcibly make them MATERIALIZED, but we * also need to run tests on older versions, so put updated plans in * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_upd_del_2.out b/expected/pathman_upd_del_2.out index 80325d7e..0826594c 100644 --- a/expected/pathman_upd_del_2.out +++ b/expected/pathman_upd_del_2.out @@ -9,6 +9,9 @@ * plans here. There is an option to forcibly make them MATERIALIZED, but we * also need to run tests on older versions, so put updated plans in * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_upd_del_3.out b/expected/pathman_upd_del_3.out index 70b41e7d..d11eb6f8 100644 --- a/expected/pathman_upd_del_3.out +++ b/expected/pathman_upd_del_3.out @@ -9,6 +9,9 @@ * plans here. There is an option to forcibly make them MATERIALIZED, but we * also need to run tests on older versions, so put updated plans in * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. */ \set VERBOSITY terse SET search_path = 'public'; diff --git a/expected/pathman_upd_del_4.out b/expected/pathman_upd_del_4.out new file mode 100644 index 00000000..54330190 --- /dev/null +++ b/expected/pathman_upd_del_4.out @@ -0,0 +1,464 @@ +/* + * ------------------------------------------- + * NOTE: This test behaves differenly on 9.5 + * ------------------------------------------- + * + * Also since 8edd0e794 (>= 12) Append nodes with single subplan are eliminated, + * causing different output. Moreover, again since 12 (608b167f9f), CTEs which are + * scanned once are no longer an optimization fence, changing a good deal of + * plans here. There is an option to forcibly make them MATERIALIZED, but we + * also need to run tests on older versions, so put updated plans in + * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. + */ +\set VERBOSITY terse +SET search_path = 'public'; +CREATE SCHEMA pathman; +CREATE EXTENSION pg_pathman SCHEMA pathman; +CREATE SCHEMA test; +SET enable_indexscan = ON; +SET enable_seqscan = OFF; +/* Temporary tables for JOINs */ +CREATE TABLE test.tmp (id INTEGER NOT NULL, value INTEGER NOT NULL); +INSERT INTO test.tmp VALUES (1, 1), (2, 2); +CREATE TABLE test.tmp2 (id INTEGER NOT NULL, value INTEGER NOT NULL); +INSERT INTO test.tmp2 SELECT i % 10 + 1, i FROM generate_series(1, 100) i; +SELECT pathman.create_range_partitions('test.tmp2', 'id', 1, 1, 10); + create_range_partitions +------------------------- + 10 +(1 row) + +/* Partition table by RANGE */ +CREATE TABLE test.range_rel ( + id SERIAL PRIMARY KEY, + dt TIMESTAMP NOT NULL, + value INTEGER); +INSERT INTO test.range_rel (dt, value) SELECT g, extract(day from g) +FROM generate_series('2010-01-01'::date, '2010-12-31'::date, '1 day') AS g; +SELECT pathman.create_range_partitions('test.range_rel', 'dt', + '2010-01-01'::date, '1 month'::interval, + 12); + create_range_partitions +------------------------- + 12 +(1 row) + +VACUUM ANALYZE; +/* + * Test UPDATE and DELETE + */ +/* have partitions for this 'dt' */ +EXPLAIN (COSTS OFF) UPDATE test.range_rel SET value = 111 WHERE dt = '2010-06-15'; + QUERY PLAN +-------------------------------------------------------------------------------- + Update on range_rel_6 + -> Seq Scan on range_rel_6 + Filter: (dt = 'Tue Jun 15 00:00:00 2010'::timestamp without time zone) +(3 rows) + +BEGIN; +UPDATE test.range_rel SET value = 111 WHERE dt = '2010-06-15'; +SELECT * FROM test.range_rel WHERE dt = '2010-06-15'; + id | dt | value +-----+--------------------------+------- + 166 | Tue Jun 15 00:00:00 2010 | 111 +(1 row) + +ROLLBACK; +/* have partitions for this 'dt' */ +EXPLAIN (COSTS OFF) DELETE FROM test.range_rel WHERE dt = '2010-06-15'; + QUERY PLAN +-------------------------------------------------------------------------------- + Delete on range_rel_6 + -> Seq Scan on range_rel_6 + Filter: (dt = 'Tue Jun 15 00:00:00 2010'::timestamp without time zone) +(3 rows) + +BEGIN; +DELETE FROM test.range_rel WHERE dt = '2010-06-15'; +SELECT * FROM test.range_rel WHERE dt = '2010-06-15'; + id | dt | value +----+----+------- +(0 rows) + +ROLLBACK; +/* no partitions for this 'dt' */ +EXPLAIN (COSTS OFF) UPDATE test.range_rel SET value = 222 WHERE dt = '1990-01-01'; + QUERY PLAN +-------------------------------------------------------------------------------- + Update on range_rel + -> Seq Scan on range_rel + Filter: (dt = 'Mon Jan 01 00:00:00 1990'::timestamp without time zone) +(3 rows) + +BEGIN; +UPDATE test.range_rel SET value = 111 WHERE dt = '1990-01-01'; +SELECT * FROM test.range_rel WHERE dt = '1990-01-01'; + id | dt | value +----+----+------- +(0 rows) + +ROLLBACK; +/* no partitions for this 'dt' */ +EXPLAIN (COSTS OFF) DELETE FROM test.range_rel WHERE dt < '1990-01-01'; + QUERY PLAN +-------------------------------------------------------------------------------- + Delete on range_rel + -> Seq Scan on range_rel + Filter: (dt < 'Mon Jan 01 00:00:00 1990'::timestamp without time zone) +(3 rows) + +BEGIN; +DELETE FROM test.range_rel WHERE dt < '1990-01-01'; +SELECT * FROM test.range_rel WHERE dt < '1990-01-01'; + id | dt | value +----+----+------- +(0 rows) + +ROLLBACK; +/* UPDATE + FROM, partitioned table */ +EXPLAIN (COSTS OFF) +UPDATE test.range_rel r SET value = t.value +FROM test.tmp t WHERE r.dt = '2010-01-01' AND r.id = t.id; + QUERY PLAN +-------------------------------------------------------------------------------------- + Update on range_rel_1 r + -> Nested Loop + Join Filter: (r.id = t.id) + -> Index Scan using range_rel_1_pkey on range_rel_1 r + Filter: (dt = 'Fri Jan 01 00:00:00 2010'::timestamp without time zone) + -> Seq Scan on tmp t +(6 rows) + +BEGIN; +UPDATE test.range_rel r SET value = t.value +FROM test.tmp t WHERE r.dt = '2010-01-01' AND r.id = t.id; +ROLLBACK; +/* UPDATE + FROM, single table */ +EXPLAIN (COSTS OFF) +UPDATE test.tmp t SET value = r.value +FROM test.range_rel r WHERE r.dt = '2010-01-01' AND r.id = t.id; + QUERY PLAN +-------------------------------------------------------------------------------------- + Update on tmp t + -> Nested Loop + -> Seq Scan on tmp t + -> Index Scan using range_rel_1_pkey on range_rel_1 r + Index Cond: (id = t.id) + Filter: (dt = 'Fri Jan 01 00:00:00 2010'::timestamp without time zone) +(6 rows) + +BEGIN; +UPDATE test.tmp t SET value = r.value +FROM test.range_rel r WHERE r.dt = '2010-01-01' AND r.id = t.id; +ROLLBACK; +/* DELETE + USING, partitioned table */ +EXPLAIN (COSTS OFF) +DELETE FROM test.range_rel r USING test.tmp t +WHERE r.dt = '2010-01-02' AND r.id = t.id; + QUERY PLAN +-------------------------------------------------------------------------------------- + Delete on range_rel_1 r + -> Nested Loop + Join Filter: (r.id = t.id) + -> Index Scan using range_rel_1_pkey on range_rel_1 r + Filter: (dt = 'Sat Jan 02 00:00:00 2010'::timestamp without time zone) + -> Seq Scan on tmp t +(6 rows) + +BEGIN; +DELETE FROM test.range_rel r USING test.tmp t +WHERE r.dt = '2010-01-02' AND r.id = t.id; +ROLLBACK; +/* DELETE + USING, single table */ +EXPLAIN (COSTS OFF) +DELETE FROM test.tmp t USING test.range_rel r +WHERE r.dt = '2010-01-02' AND r.id = t.id; + QUERY PLAN +-------------------------------------------------------------------------------------- + Delete on tmp t + -> Nested Loop + -> Seq Scan on tmp t + -> Index Scan using range_rel_1_pkey on range_rel_1 r + Index Cond: (id = t.id) + Filter: (dt = 'Sat Jan 02 00:00:00 2010'::timestamp without time zone) +(6 rows) + +BEGIN; +DELETE FROM test.tmp t USING test.range_rel r +WHERE r.dt = '2010-01-02' AND r.id = t.id; +ROLLBACK; +/* DELETE + USING, two partitioned tables */ +EXPLAIN (COSTS OFF) +DELETE FROM test.range_rel r USING test.tmp2 t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +BEGIN; +DELETE FROM test.range_rel r USING test.tmp2 t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +ROLLBACK; +/* DELETE + USING, partitioned table + two partitioned tables in subselect */ +EXPLAIN (COSTS OFF) +DELETE FROM test.range_rel r +USING (SELECT * + FROM test.tmp2 a1 + JOIN test.tmp2 a2 + USING(id)) t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +BEGIN; +DELETE FROM test.range_rel r +USING (SELECT * + FROM test.tmp2 a1 + JOIN test.tmp2 a2 + USING(id)) t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +ROLLBACK; +/* DELETE + USING, single table + two partitioned tables in subselect */ +EXPLAIN (COSTS OFF) +DELETE FROM test.tmp r +USING (SELECT * + FROM test.tmp2 a1 + JOIN test.tmp2 a2 + USING(id)) t +WHERE t.id = r.id; + QUERY PLAN +------------------------------------------------ + Delete on tmp r + -> Nested Loop + -> Nested Loop + -> Seq Scan on tmp r + -> Custom Scan (RuntimeAppend) + Prune by: (r.id = a1.id) + -> Seq Scan on tmp2_1 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_2 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_3 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_4 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_5 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_6 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_7 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_8 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_9 a1 + Filter: (r.id = id) + -> Seq Scan on tmp2_10 a1 + Filter: (r.id = id) + -> Custom Scan (RuntimeAppend) + Prune by: (a1.id = a2.id) + -> Seq Scan on tmp2_1 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_2 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_3 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_4 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_5 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_6 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_7 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_8 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_9 a2 + Filter: (a1.id = id) + -> Seq Scan on tmp2_10 a2 + Filter: (a1.id = id) +(48 rows) + +BEGIN; +DELETE FROM test.tmp r +USING (SELECT * + FROM test.tmp2 a1 + JOIN test.tmp2 a2 + USING(id)) t +WHERE t.id = r.id; +ROLLBACK; +/* UPDATE + FROM, two partitioned tables */ +EXPLAIN (COSTS OFF) +UPDATE test.range_rel r SET value = 1 FROM test.tmp2 t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +BEGIN; +UPDATE test.range_rel r SET value = 1 FROM test.tmp2 t +WHERE t.id = r.id; +ERROR: DELETE and UPDATE queries with a join of partitioned tables are not supported +ROLLBACK; +/* + * UPDATE + subquery with partitioned table (PG 9.5). + * See pathman_rel_pathlist_hook() + RELOPT_OTHER_MEMBER_REL. + */ +EXPLAIN (COSTS OFF) +UPDATE test.tmp t SET value = 2 +WHERE t.id IN (SELECT id + FROM test.tmp2 t2 + WHERE id = t.id); + QUERY PLAN +------------------------------------------ + Update on tmp t + -> Nested Loop Semi Join + -> Seq Scan on tmp t + -> Custom Scan (RuntimeAppend) + Prune by: (t.id = t2.id) + -> Seq Scan on tmp2_1 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_2 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_3 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_4 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_5 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_6 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_7 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_8 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_9 t2 + Filter: (t.id = id) + -> Seq Scan on tmp2_10 t2 + Filter: (t.id = id) +(25 rows) + +/* Test special rule for CTE; SELECT (PostgreSQL 9.5) */ +EXPLAIN (COSTS OFF) +WITH q AS (SELECT * FROM test.range_rel r + WHERE r.dt = '2010-01-02') +DELETE FROM test.tmp USING q; + QUERY PLAN +-------------------------------------------------------------------------------------------- + Delete on tmp + -> Nested Loop + -> Seq Scan on tmp + -> Materialize + -> Seq Scan on range_rel_1 r + Filter: (dt = 'Sat Jan 02 00:00:00 2010'::timestamp without time zone) +(6 rows) + +BEGIN; +WITH q AS (SELECT * FROM test.range_rel r + WHERE r.dt = '2010-01-02') +DELETE FROM test.tmp USING q; +ROLLBACK; +/* Test special rule for CTE; DELETE (PostgreSQL 9.5) */ +EXPLAIN (COSTS OFF) +WITH q AS (DELETE FROM test.range_rel r + WHERE r.dt = '2010-01-02' + RETURNING *) +DELETE FROM test.tmp USING q; + QUERY PLAN +---------------------------------------------------------------------------------------- + Delete on tmp + CTE q + -> Delete on range_rel_1 r + -> Seq Scan on range_rel_1 r + Filter: (dt = 'Sat Jan 02 00:00:00 2010'::timestamp without time zone) + -> Nested Loop + -> Seq Scan on tmp + -> CTE Scan on q +(8 rows) + +BEGIN; +WITH q AS (DELETE FROM test.range_rel r + WHERE r.dt = '2010-01-02' + RETURNING *) +DELETE FROM test.tmp USING q; +ROLLBACK; +/* Test special rule for CTE; DELETE + USING (PostgreSQL 9.5) */ +EXPLAIN (COSTS OFF) +WITH q AS (DELETE FROM test.tmp t + USING test.range_rel r + WHERE r.dt = '2010-01-02' AND r.id = t.id + RETURNING *) +DELETE FROM test.tmp USING q; + QUERY PLAN +---------------------------------------------------------------------------------------------- + Delete on tmp + CTE q + -> Delete on tmp t + -> Nested Loop + -> Seq Scan on tmp t + -> Index Scan using range_rel_1_pkey on range_rel_1 r + Index Cond: (id = t.id) + Filter: (dt = 'Sat Jan 02 00:00:00 2010'::timestamp without time zone) + -> Nested Loop + -> Seq Scan on tmp + -> CTE Scan on q +(11 rows) + +BEGIN; +WITH q AS (DELETE FROM test.tmp t + USING test.range_rel r + WHERE r.dt = '2010-01-02' AND r.id = t.id + RETURNING *) +DELETE FROM test.tmp USING q; +ROLLBACK; +/* Test special rule for CTE; Nested CTEs (PostgreSQL 9.5) */ +EXPLAIN (COSTS OFF) +WITH q AS (WITH n AS (SELECT id FROM test.tmp2 WHERE id = 2) + DELETE FROM test.tmp t + USING n + WHERE t.id = n.id + RETURNING *) +DELETE FROM test.tmp USING q; + QUERY PLAN +--------------------------------------------- + Delete on tmp + CTE q + -> Delete on tmp t + -> Nested Loop + -> Seq Scan on tmp t + Filter: (id = 2) + -> Seq Scan on tmp2_2 tmp2 + Filter: (id = 2) + -> Nested Loop + -> Seq Scan on tmp + -> CTE Scan on q +(11 rows) + +/* Test special rule for CTE; CTE in quals (PostgreSQL 9.5) */ +EXPLAIN (COSTS OFF) +WITH q AS (SELECT id FROM test.tmp2 + WHERE id < 3) +DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q); + QUERY PLAN +-------------------------------------------------------------- + Delete on tmp t + -> Nested Loop Semi Join + -> Seq Scan on tmp t + -> Custom Scan (RuntimeAppend) + Prune by: ((tmp2.id < 3) AND (t.id = tmp2.id)) + -> Seq Scan on tmp2_1 tmp2 + Filter: (t.id = id) + -> Seq Scan on tmp2_2 tmp2 + Filter: (t.id = id) +(9 rows) + +BEGIN; +WITH q AS (SELECT id FROM test.tmp2 + WHERE id < 3) +DELETE FROM test.tmp t WHERE t.id in (SELECT id FROM q); +ROLLBACK; +DROP TABLE test.tmp CASCADE; +DROP TABLE test.tmp2 CASCADE; +NOTICE: drop cascades to 11 other objects +DROP TABLE test.range_rel CASCADE; +NOTICE: drop cascades to 13 other objects +DROP SCHEMA test; +DROP EXTENSION pg_pathman CASCADE; +DROP SCHEMA pathman; diff --git a/sql/pathman_upd_del.sql b/sql/pathman_upd_del.sql index a034c14a..c99b9666 100644 --- a/sql/pathman_upd_del.sql +++ b/sql/pathman_upd_del.sql @@ -9,6 +9,9 @@ * plans here. There is an option to forcibly make them MATERIALIZED, but we * also need to run tests on older versions, so put updated plans in * pathman_upd_del_2.out instead. + * + * In Postgres Pro Standard/Enterprise 15+ the EXPLAIN output has changed so put + * the updated plan in pathman_upd_del_4.out. */ \set VERBOSITY terse From a0fd611a55f2a0fe3712a8e96b8e5bdd24794aa3 Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Wed, 28 May 2025 23:49:59 +0300 Subject: [PATCH 4/7] [PGPRO-13804] Save original RTEPermissionInfo array before adding a new element --- src/partition_filter.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/partition_filter.c b/src/partition_filter.c index 3d5e4bd3..76c864df 100644 --- a/src/partition_filter.c +++ b/src/partition_filter.c @@ -51,6 +51,9 @@ typedef struct { int estate_alloc_result_rels; /* number of allocated result rels */ bool estate_not_modified; /* did we modify EState somehow? */ +#if PG_VERSION_NUM >= 160000 + bool perminfo_not_modified; /* did we change the estate->es_rteperminfos field? */ +#endif } estate_mod_data; /* @@ -95,6 +98,9 @@ static Node *fix_returning_list_mutator(Node *node, void *state); static Index append_rte_to_estate(EState *estate, RangeTblEntry *rte, Relation child_rel); static int append_rri_to_estate(EState *estate, ResultRelInfo *rri); +#if PG_VERSION_NUM >= 160000 +static void prepare_estate_for_append_perminfo(EState *estate); +#endif static void pf_memcxt_callback(void *arg); static estate_mod_data * fetch_estate_mod_data(EState *estate); @@ -337,6 +343,7 @@ scan_result_parts_storage(EState *estate, ResultPartsStorage *parts_storage, parent_perminfo = getRTEPermissionInfo(estate->es_rteperminfos, init_rte); child_rte->perminfoindex = 0; /* expected by addRTEPermissionInfo() */ + prepare_estate_for_append_perminfo(estate); child_perminfo = addRTEPermissionInfo(&estate->es_rteperminfos, child_rte); child_perminfo->requiredPerms = parent_perminfo->requiredPerms; child_perminfo->checkAsUser = parent_perminfo->checkAsUser; @@ -1449,6 +1456,22 @@ fix_returning_list_mutator(Node *node, void *state) * ------------------------------------- */ +#if PG_VERSION_NUM >= 160000 +/* Prepare estate->es_rteperminfos for append RTEPermissionInfo */ +static void +prepare_estate_for_append_perminfo(EState *estate) +{ + estate_mod_data *emd_struct = fetch_estate_mod_data(estate); + + /* Copy estate->es_rteperminfos if it's first time expansion. */ + if (emd_struct->perminfo_not_modified) + estate->es_rteperminfos = list_copy(estate->es_rteperminfos); + + /* Update estate_mod_data. */ + emd_struct->perminfo_not_modified = false; +} +#endif + /* Append RangeTblEntry 'rte' to estate->es_range_table */ static Index append_rte_to_estate(EState *estate, RangeTblEntry *rte, Relation child_rel) @@ -1594,6 +1617,9 @@ fetch_estate_mod_data(EState *estate) /* Have to create a new one */ emd_struct = MemoryContextAlloc(estate_mcxt, sizeof(estate_mod_data)); emd_struct->estate_not_modified = true; +#if PG_VERSION_NUM >= 160000 + emd_struct->perminfo_not_modified = true; +#endif #if PG_VERSION_NUM >= 140000 /* * Reworked in commit a04daa97a433: field "es_num_result_relations" From e3092cbad3dbf3d45c4eb8d6f358969ec0aba122 Mon Sep 17 00:00:00 2001 From: Karina Litskevich Date: Fri, 22 Aug 2025 13:19:01 +0300 Subject: [PATCH 5/7] [PGPRO-14441] Add "regress_" prefix to roles in test Tags: pg_pathman --- expected/pathman_CVE-2020-14350.out | 22 +++--- expected/pathman_permissions.out | 116 ++++++++++++++-------------- expected/pathman_permissions_1.out | 116 ++++++++++++++-------------- sql/pathman_CVE-2020-14350.sql | 22 +++--- sql/pathman_permissions.sql | 64 +++++++-------- 5 files changed, 170 insertions(+), 170 deletions(-) diff --git a/expected/pathman_CVE-2020-14350.out b/expected/pathman_CVE-2020-14350.out index a48e182f..9037364a 100644 --- a/expected/pathman_CVE-2020-14350.out +++ b/expected/pathman_CVE-2020-14350.out @@ -7,15 +7,15 @@ DROP FUNCTION IF EXISTS _partition_data_concurrent(oid,integer); DROP FUNCTION IF EXISTS create_single_range_partition(TEXT,ANYELEMENT,ANYELEMENT,TEXT); DROP TABLE IF EXISTS test1 CASCADE; DROP TABLE IF EXISTS test2 CASCADE; -DROP ROLE IF EXISTS pathman_regress_hacker; +DROP ROLE IF EXISTS regress_pathman_hacker; SET client_min_messages = 'notice'; GRANT CREATE ON SCHEMA public TO PUBLIC; CREATE EXTENSION pg_pathman; -CREATE ROLE pathman_regress_hacker LOGIN; +CREATE ROLE regress_pathman_hacker LOGIN; -- Test 1 RESET ROLE; -ALTER ROLE pathman_regress_hacker NOSUPERUSER; -SET ROLE pathman_regress_hacker; +ALTER ROLE regress_pathman_hacker NOSUPERUSER; +SET ROLE regress_pathman_hacker; SHOW is_superuser; is_superuser -------------- @@ -26,7 +26,7 @@ CREATE FUNCTION _partition_data_concurrent(relation oid, p_limit INT, OUT p_tota RETURNS bigint AS $$ BEGIN - ALTER ROLE pathman_regress_hacker SUPERUSER; + ALTER ROLE regress_pathman_hacker SUPERUSER; SELECT _partition_data_concurrent(relation, NULL::text, NULL::text, p_limit) INTO p_total; END $$ LANGUAGE plpgsql; @@ -53,7 +53,7 @@ SELECT pg_sleep(1); (1 row) -- Test result (must be 'off') -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; is_superuser -------------- @@ -62,8 +62,8 @@ SHOW is_superuser; -- Test 2 RESET ROLE; -ALTER ROLE pathman_regress_hacker NOSUPERUSER; -SET ROLE pathman_regress_hacker; +ALTER ROLE regress_pathman_hacker NOSUPERUSER; +SET ROLE regress_pathman_hacker; SHOW is_superuser; is_superuser -------------- @@ -74,7 +74,7 @@ CREATE FUNCTION create_single_range_partition(parent_relid TEXT, start_value ANY RETURNS REGCLASS AS $$ BEGIN - ALTER ROLE pathman_regress_hacker SUPERUSER; + ALTER ROLE regress_pathman_hacker SUPERUSER; RETURN create_single_range_partition(parent_relid, start_value, end_value, partition_name, NULL::text); END $$ LANGUAGE plpgsql; @@ -89,7 +89,7 @@ SELECT create_range_partitions('test2', 'i', 0, 1); INSERT INTO test2 values(1); -- Test result (must be 'off') -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; is_superuser -------------- @@ -112,5 +112,5 @@ NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to sequence test2_seq drop cascades to table test2_1 drop cascades to table test2_2 -DROP ROLE pathman_regress_hacker; +DROP ROLE regress_pathman_hacker; DROP EXTENSION pg_pathman; diff --git a/expected/pathman_permissions.out b/expected/pathman_permissions.out index a29865d0..b0864649 100644 --- a/expected/pathman_permissions.out +++ b/expected/pathman_permissions.out @@ -2,16 +2,16 @@ SET search_path = 'public'; CREATE EXTENSION pg_pathman; CREATE SCHEMA permissions; -CREATE ROLE pathman_user1 LOGIN; -CREATE ROLE pathman_user2 LOGIN; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user1; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user2; +CREATE ROLE regress_pathman_user1 LOGIN; +CREATE ROLE regress_pathman_user2 LOGIN; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user1; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user2; /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.pathman_user1_table(id serial, a int); INSERT INTO permissions.pathman_user1_table SELECT g, g FROM generate_series(1, 20) as g; /* Should fail (can't SELECT) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -20,11 +20,11 @@ EXCEPTION RAISE NOTICE 'Insufficient priviliges'; END$$; NOTICE: Insufficient priviliges -/* Grant SELECT to pathman_user2 */ -SET ROLE pathman_user1; -GRANT SELECT ON permissions.pathman_user1_table TO pathman_user2; +/* Grant SELECT to regress_pathman_user2 */ +SET ROLE regress_pathman_user1; +GRANT SELECT ON permissions.pathman_user1_table TO regress_pathman_user2; /* Should fail (don't own parent) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -34,7 +34,7 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* Should be ok */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); create_range_partitions ------------------------- @@ -42,7 +42,7 @@ SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2 (1 row) /* Should be able to see */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT * FROM pathman_config; partrel | expr | parttype | range_interval ---------------------------------+------+----------+---------------- @@ -56,7 +56,7 @@ SELECT * FROM pathman_config_params; (1 row) /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT set_enable_parent('permissions.pathman_user1_table', true); WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" ERROR: new row violates row-level security policy for table "pathman_config_params" @@ -64,12 +64,12 @@ SELECT set_auto('permissions.pathman_user1_table', false); WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" ERROR: new row violates row-level security policy for table "pathman_config_params" /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DELETE FROM pathman_config WHERE partrel = 'permissions.pathman_user1_table'::regclass; WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" /* No rights to insert, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0); @@ -79,15 +79,15 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* No rights to create partitions (need INSERT privilege) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); ERROR: permission denied for parent relation "pathman_user1_table" -/* Allow pathman_user2 to create partitions */ -SET ROLE pathman_user1; -GRANT INSERT ON permissions.pathman_user1_table TO pathman_user2; -GRANT UPDATE(a) ON permissions.pathman_user1_table TO pathman_user2; /* per-column ACL */ +/* Allow regress_pathman_user2 to create partitions */ +SET ROLE regress_pathman_user1; +GRANT INSERT ON permissions.pathman_user1_table TO regress_pathman_user2; +GRANT UPDATE(a) ON permissions.pathman_user1_table TO regress_pathman_user2; /* per-column ACL */ /* Should be able to prepend a partition */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); prepend_range_partition ----------------------------------- @@ -100,9 +100,9 @@ WHERE attrelid = (SELECT "partition" FROM pathman_partition_list ORDER BY range_min::int ASC /* prepend */ LIMIT 1) ORDER BY attname; /* check ACL for each column */ - attname | attacl -----------+--------------------------------- - a | {pathman_user2=w/pathman_user1} + attname | attacl +----------+------------------------------------------------- + a | {regress_pathman_user2=w/regress_pathman_user1} cmax | cmin | ctid | @@ -113,7 +113,7 @@ ORDER BY attname; /* check ACL for each column */ (8 rows) /* Have rights, should be ok (parent's ACL is shared by new children) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0) RETURNING *; id | a ----+--- @@ -126,11 +126,11 @@ WHERE oid = ANY (SELECT "partition" FROM pathman_partition_list ORDER BY range_max::int DESC /* append */ LIMIT 3) ORDER BY relname; /* we also check ACL for "pathman_user1_table_2" */ - relname | relacl ------------------------+---------------------------------------------------------------------- - pathman_user1_table_2 | {pathman_user1=arwdDxt/pathman_user1,pathman_user2=r/pathman_user1} - pathman_user1_table_5 | {pathman_user1=arwdDxt/pathman_user1,pathman_user2=ar/pathman_user1} - pathman_user1_table_6 | {pathman_user1=arwdDxt/pathman_user1,pathman_user2=ar/pathman_user1} + relname | relacl +-----------------------+------------------------------------------------------------------------------------------------------ + pathman_user1_table_2 | {regress_pathman_user1=arwdDxt/regress_pathman_user1,regress_pathman_user2=r/regress_pathman_user1} + pathman_user1_table_5 | {regress_pathman_user1=arwdDxt/regress_pathman_user1,regress_pathman_user2=ar/regress_pathman_user1} + pathman_user1_table_6 | {regress_pathman_user1=arwdDxt/regress_pathman_user1,regress_pathman_user2=ar/regress_pathman_user1} (3 rows) /* Try to drop partition, should fail */ @@ -143,7 +143,7 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* Disable automatic partition creation */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT set_auto('permissions.pathman_user1_table', false); set_auto ---------- @@ -151,11 +151,11 @@ SELECT set_auto('permissions.pathman_user1_table', false); (1 row) /* Partition creation, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (55, 0) RETURNING *; ERROR: no suitable partition for key '55' /* Finally drop partitions */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT drop_partitions('permissions.pathman_user1_table'); NOTICE: 10 rows copied from permissions.pathman_user1_table_1 NOTICE: 10 rows copied from permissions.pathman_user1_table_2 @@ -168,7 +168,7 @@ NOTICE: 1 rows copied from permissions.pathman_user1_table_6 (1 row) /* Switch to #2 */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; /* Test ddl event trigger */ CREATE TABLE permissions.pathman_user2_table(id serial); SELECT create_hash_partitions('permissions.pathman_user2_table', 'id', 3); @@ -188,10 +188,10 @@ NOTICE: 10 rows copied from permissions.pathman_user2_table_2 (1 row) /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.dropped_column(a int, val int not null, b int, c int); INSERT INTO permissions.dropped_column SELECT i,i,i,i FROM generate_series(1, 30) i; -GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO pathman_user2; +GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO regress_pathman_user2; SELECT create_range_partitions('permissions.dropped_column', 'val', 1, 10); create_range_partitions ------------------------- @@ -203,11 +203,11 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} (3 rows) ALTER TABLE permissions.dropped_column DROP COLUMN a; /* DROP "a" */ @@ -222,12 +222,12 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_4 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_4 | val | {regress_pathman_user2=ar/regress_pathman_user1} (4 rows) ALTER TABLE permissions.dropped_column DROP COLUMN b; /* DROP "b" */ @@ -242,22 +242,22 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_4 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_5 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_4 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_5 | val | {regress_pathman_user2=ar/regress_pathman_user1} (5 rows) DROP TABLE permissions.dropped_column CASCADE; NOTICE: drop cascades to 6 other objects /* Finally reset user */ RESET ROLE; -DROP OWNED BY pathman_user1; -DROP OWNED BY pathman_user2; -DROP USER pathman_user1; -DROP USER pathman_user2; +DROP OWNED BY regress_pathman_user1; +DROP OWNED BY regress_pathman_user2; +DROP USER regress_pathman_user1; +DROP USER regress_pathman_user2; DROP SCHEMA permissions; DROP EXTENSION pg_pathman; diff --git a/expected/pathman_permissions_1.out b/expected/pathman_permissions_1.out index dc976aae..12767eb3 100644 --- a/expected/pathman_permissions_1.out +++ b/expected/pathman_permissions_1.out @@ -2,16 +2,16 @@ SET search_path = 'public'; CREATE EXTENSION pg_pathman; CREATE SCHEMA permissions; -CREATE ROLE pathman_user1 LOGIN; -CREATE ROLE pathman_user2 LOGIN; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user1; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user2; +CREATE ROLE regress_pathman_user1 LOGIN; +CREATE ROLE regress_pathman_user2 LOGIN; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user1; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user2; /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.pathman_user1_table(id serial, a int); INSERT INTO permissions.pathman_user1_table SELECT g, g FROM generate_series(1, 20) as g; /* Should fail (can't SELECT) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -20,11 +20,11 @@ EXCEPTION RAISE NOTICE 'Insufficient priviliges'; END$$; NOTICE: Insufficient priviliges -/* Grant SELECT to pathman_user2 */ -SET ROLE pathman_user1; -GRANT SELECT ON permissions.pathman_user1_table TO pathman_user2; +/* Grant SELECT to regress_pathman_user2 */ +SET ROLE regress_pathman_user1; +GRANT SELECT ON permissions.pathman_user1_table TO regress_pathman_user2; /* Should fail (don't own parent) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -34,7 +34,7 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* Should be ok */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); create_range_partitions ------------------------- @@ -42,7 +42,7 @@ SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2 (1 row) /* Should be able to see */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT * FROM pathman_config; partrel | expr | parttype | range_interval ---------------------------------+------+----------+---------------- @@ -56,7 +56,7 @@ SELECT * FROM pathman_config_params; (1 row) /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT set_enable_parent('permissions.pathman_user1_table', true); WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" ERROR: new row violates row-level security policy for table "pathman_config_params" @@ -64,12 +64,12 @@ SELECT set_auto('permissions.pathman_user1_table', false); WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" ERROR: new row violates row-level security policy for table "pathman_config_params" /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DELETE FROM pathman_config WHERE partrel = 'permissions.pathman_user1_table'::regclass; WARNING: only the owner or superuser can change partitioning configuration of table "pathman_user1_table" /* No rights to insert, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0); @@ -79,15 +79,15 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* No rights to create partitions (need INSERT privilege) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); ERROR: permission denied for parent relation "pathman_user1_table" -/* Allow pathman_user2 to create partitions */ -SET ROLE pathman_user1; -GRANT INSERT ON permissions.pathman_user1_table TO pathman_user2; -GRANT UPDATE(a) ON permissions.pathman_user1_table TO pathman_user2; /* per-column ACL */ +/* Allow regress_pathman_user2 to create partitions */ +SET ROLE regress_pathman_user1; +GRANT INSERT ON permissions.pathman_user1_table TO regress_pathman_user2; +GRANT UPDATE(a) ON permissions.pathman_user1_table TO regress_pathman_user2; /* per-column ACL */ /* Should be able to prepend a partition */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); prepend_range_partition ----------------------------------- @@ -100,9 +100,9 @@ WHERE attrelid = (SELECT "partition" FROM pathman_partition_list ORDER BY range_min::int ASC /* prepend */ LIMIT 1) ORDER BY attname; /* check ACL for each column */ - attname | attacl -----------+--------------------------------- - a | {pathman_user2=w/pathman_user1} + attname | attacl +----------+------------------------------------------------- + a | {regress_pathman_user2=w/regress_pathman_user1} cmax | cmin | ctid | @@ -113,7 +113,7 @@ ORDER BY attname; /* check ACL for each column */ (8 rows) /* Have rights, should be ok (parent's ACL is shared by new children) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0) RETURNING *; id | a ----+--- @@ -126,11 +126,11 @@ WHERE oid = ANY (SELECT "partition" FROM pathman_partition_list ORDER BY range_max::int DESC /* append */ LIMIT 3) ORDER BY relname; /* we also check ACL for "pathman_user1_table_2" */ - relname | relacl ------------------------+----------------------------------------------------------------------- - pathman_user1_table_2 | {pathman_user1=arwdDxtm/pathman_user1,pathman_user2=r/pathman_user1} - pathman_user1_table_5 | {pathman_user1=arwdDxtm/pathman_user1,pathman_user2=ar/pathman_user1} - pathman_user1_table_6 | {pathman_user1=arwdDxtm/pathman_user1,pathman_user2=ar/pathman_user1} + relname | relacl +-----------------------+------------------------------------------------------------------------------------------------------- + pathman_user1_table_2 | {regress_pathman_user1=arwdDxtm/regress_pathman_user1,regress_pathman_user2=r/regress_pathman_user1} + pathman_user1_table_5 | {regress_pathman_user1=arwdDxtm/regress_pathman_user1,regress_pathman_user2=ar/regress_pathman_user1} + pathman_user1_table_6 | {regress_pathman_user1=arwdDxtm/regress_pathman_user1,regress_pathman_user2=ar/regress_pathman_user1} (3 rows) /* Try to drop partition, should fail */ @@ -143,7 +143,7 @@ EXCEPTION END$$; NOTICE: Insufficient priviliges /* Disable automatic partition creation */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT set_auto('permissions.pathman_user1_table', false); set_auto ---------- @@ -151,11 +151,11 @@ SELECT set_auto('permissions.pathman_user1_table', false); (1 row) /* Partition creation, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (55, 0) RETURNING *; ERROR: no suitable partition for key '55' /* Finally drop partitions */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT drop_partitions('permissions.pathman_user1_table'); NOTICE: 10 rows copied from permissions.pathman_user1_table_1 NOTICE: 10 rows copied from permissions.pathman_user1_table_2 @@ -168,7 +168,7 @@ NOTICE: 1 rows copied from permissions.pathman_user1_table_6 (1 row) /* Switch to #2 */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; /* Test ddl event trigger */ CREATE TABLE permissions.pathman_user2_table(id serial); SELECT create_hash_partitions('permissions.pathman_user2_table', 'id', 3); @@ -188,10 +188,10 @@ NOTICE: 10 rows copied from permissions.pathman_user2_table_2 (1 row) /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.dropped_column(a int, val int not null, b int, c int); INSERT INTO permissions.dropped_column SELECT i,i,i,i FROM generate_series(1, 30) i; -GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO pathman_user2; +GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO regress_pathman_user2; SELECT create_range_partitions('permissions.dropped_column', 'val', 1, 10); create_range_partitions ------------------------- @@ -203,11 +203,11 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} (3 rows) ALTER TABLE permissions.dropped_column DROP COLUMN a; /* DROP "a" */ @@ -222,12 +222,12 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_4 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_4 | val | {regress_pathman_user2=ar/regress_pathman_user1} (4 rows) ALTER TABLE permissions.dropped_column DROP COLUMN b; /* DROP "b" */ @@ -242,22 +242,22 @@ WHERE attrelid = ANY (SELECT "partition" FROM pathman_partition_list WHERE parent = 'permissions.dropped_column'::REGCLASS) AND attacl IS NOT NULL ORDER BY attrelid::regclass::text; /* check ACL for each column (+1 partition) */ - attrelid | attname | attacl -------------------------------+---------+---------------------------------- - permissions.dropped_column_1 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_2 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_3 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_4 | val | {pathman_user2=ar/pathman_user1} - permissions.dropped_column_5 | val | {pathman_user2=ar/pathman_user1} + attrelid | attname | attacl +------------------------------+---------+-------------------------------------------------- + permissions.dropped_column_1 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_2 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_3 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_4 | val | {regress_pathman_user2=ar/regress_pathman_user1} + permissions.dropped_column_5 | val | {regress_pathman_user2=ar/regress_pathman_user1} (5 rows) DROP TABLE permissions.dropped_column CASCADE; NOTICE: drop cascades to 6 other objects /* Finally reset user */ RESET ROLE; -DROP OWNED BY pathman_user1; -DROP OWNED BY pathman_user2; -DROP USER pathman_user1; -DROP USER pathman_user2; +DROP OWNED BY regress_pathman_user1; +DROP OWNED BY regress_pathman_user2; +DROP USER regress_pathman_user1; +DROP USER regress_pathman_user2; DROP SCHEMA permissions; DROP EXTENSION pg_pathman; diff --git a/sql/pathman_CVE-2020-14350.sql b/sql/pathman_CVE-2020-14350.sql index 07daa617..de3cf6e9 100644 --- a/sql/pathman_CVE-2020-14350.sql +++ b/sql/pathman_CVE-2020-14350.sql @@ -8,24 +8,24 @@ DROP FUNCTION IF EXISTS _partition_data_concurrent(oid,integer); DROP FUNCTION IF EXISTS create_single_range_partition(TEXT,ANYELEMENT,ANYELEMENT,TEXT); DROP TABLE IF EXISTS test1 CASCADE; DROP TABLE IF EXISTS test2 CASCADE; -DROP ROLE IF EXISTS pathman_regress_hacker; +DROP ROLE IF EXISTS regress_pathman_hacker; SET client_min_messages = 'notice'; GRANT CREATE ON SCHEMA public TO PUBLIC; CREATE EXTENSION pg_pathman; -CREATE ROLE pathman_regress_hacker LOGIN; +CREATE ROLE regress_pathman_hacker LOGIN; -- Test 1 RESET ROLE; -ALTER ROLE pathman_regress_hacker NOSUPERUSER; +ALTER ROLE regress_pathman_hacker NOSUPERUSER; -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; CREATE FUNCTION _partition_data_concurrent(relation oid, p_limit INT, OUT p_total BIGINT) RETURNS bigint AS $$ BEGIN - ALTER ROLE pathman_regress_hacker SUPERUSER; + ALTER ROLE regress_pathman_hacker SUPERUSER; SELECT _partition_data_concurrent(relation, NULL::text, NULL::text, p_limit) INTO p_total; END $$ LANGUAGE plpgsql; @@ -39,20 +39,20 @@ SELECT partition_table_concurrently('test1', 10, 1); SELECT pg_sleep(1); -- Test result (must be 'off') -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; -- Test 2 RESET ROLE; -ALTER ROLE pathman_regress_hacker NOSUPERUSER; +ALTER ROLE regress_pathman_hacker NOSUPERUSER; -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; CREATE FUNCTION create_single_range_partition(parent_relid TEXT, start_value ANYELEMENT, end_value ANYELEMENT, partition_name TEXT) RETURNS REGCLASS AS $$ BEGIN - ALTER ROLE pathman_regress_hacker SUPERUSER; + ALTER ROLE regress_pathman_hacker SUPERUSER; RETURN create_single_range_partition(parent_relid, start_value, end_value, partition_name, NULL::text); END $$ LANGUAGE plpgsql; @@ -64,7 +64,7 @@ SELECT create_range_partitions('test2', 'i', 0, 1); INSERT INTO test2 values(1); -- Test result (must be 'off') -SET ROLE pathman_regress_hacker; +SET ROLE regress_pathman_hacker; SHOW is_superuser; -- Cleanup @@ -73,6 +73,6 @@ DROP FUNCTION _partition_data_concurrent(oid,integer); DROP FUNCTION create_single_range_partition(TEXT,ANYELEMENT,ANYELEMENT,TEXT); DROP TABLE test1 CASCADE; DROP TABLE test2 CASCADE; -DROP ROLE pathman_regress_hacker; +DROP ROLE regress_pathman_hacker; DROP EXTENSION pg_pathman; diff --git a/sql/pathman_permissions.sql b/sql/pathman_permissions.sql index 3e2cf92a..4dde907e 100644 --- a/sql/pathman_permissions.sql +++ b/sql/pathman_permissions.sql @@ -4,20 +4,20 @@ SET search_path = 'public'; CREATE EXTENSION pg_pathman; CREATE SCHEMA permissions; -CREATE ROLE pathman_user1 LOGIN; -CREATE ROLE pathman_user2 LOGIN; +CREATE ROLE regress_pathman_user1 LOGIN; +CREATE ROLE regress_pathman_user2 LOGIN; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user1; -GRANT USAGE, CREATE ON SCHEMA permissions TO pathman_user2; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user1; +GRANT USAGE, CREATE ON SCHEMA permissions TO regress_pathman_user2; /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.pathman_user1_table(id serial, a int); INSERT INTO permissions.pathman_user1_table SELECT g, g FROM generate_series(1, 20) as g; /* Should fail (can't SELECT) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -26,12 +26,12 @@ EXCEPTION RAISE NOTICE 'Insufficient priviliges'; END$$; -/* Grant SELECT to pathman_user2 */ -SET ROLE pathman_user1; -GRANT SELECT ON permissions.pathman_user1_table TO pathman_user2; +/* Grant SELECT to regress_pathman_user2 */ +SET ROLE regress_pathman_user1; +GRANT SELECT ON permissions.pathman_user1_table TO regress_pathman_user2; /* Should fail (don't own parent) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); @@ -41,26 +41,26 @@ EXCEPTION END$$; /* Should be ok */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT create_range_partitions('permissions.pathman_user1_table', 'id', 1, 10, 2); /* Should be able to see */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT * FROM pathman_config; SELECT * FROM pathman_config_params; /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT set_enable_parent('permissions.pathman_user1_table', true); SELECT set_auto('permissions.pathman_user1_table', false); /* Should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DELETE FROM pathman_config WHERE partrel = 'permissions.pathman_user1_table'::regclass; /* No rights to insert, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; DO $$ BEGIN INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0); @@ -70,16 +70,16 @@ EXCEPTION END$$; /* No rights to create partitions (need INSERT privilege) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); -/* Allow pathman_user2 to create partitions */ -SET ROLE pathman_user1; -GRANT INSERT ON permissions.pathman_user1_table TO pathman_user2; -GRANT UPDATE(a) ON permissions.pathman_user1_table TO pathman_user2; /* per-column ACL */ +/* Allow regress_pathman_user2 to create partitions */ +SET ROLE regress_pathman_user1; +GRANT INSERT ON permissions.pathman_user1_table TO regress_pathman_user2; +GRANT UPDATE(a) ON permissions.pathman_user1_table TO regress_pathman_user2; /* per-column ACL */ /* Should be able to prepend a partition */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; SELECT prepend_range_partition('permissions.pathman_user1_table'); SELECT attname, attacl FROM pg_attribute WHERE attrelid = (SELECT "partition" FROM pathman_partition_list @@ -89,7 +89,7 @@ WHERE attrelid = (SELECT "partition" FROM pathman_partition_list ORDER BY attname; /* check ACL for each column */ /* Have rights, should be ok (parent's ACL is shared by new children) */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (35, 0) RETURNING *; SELECT relname, relacl FROM pg_class WHERE oid = ANY (SELECT "partition" FROM pathman_partition_list @@ -108,20 +108,20 @@ EXCEPTION END$$; /* Disable automatic partition creation */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT set_auto('permissions.pathman_user1_table', false); /* Partition creation, should fail */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; INSERT INTO permissions.pathman_user1_table (id, a) VALUES (55, 0) RETURNING *; /* Finally drop partitions */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; SELECT drop_partitions('permissions.pathman_user1_table'); /* Switch to #2 */ -SET ROLE pathman_user2; +SET ROLE regress_pathman_user2; /* Test ddl event trigger */ CREATE TABLE permissions.pathman_user2_table(id serial); SELECT create_hash_partitions('permissions.pathman_user2_table', 'id', 3); @@ -130,11 +130,11 @@ SELECT drop_partitions('permissions.pathman_user2_table'); /* Switch to #1 */ -SET ROLE pathman_user1; +SET ROLE regress_pathman_user1; CREATE TABLE permissions.dropped_column(a int, val int not null, b int, c int); INSERT INTO permissions.dropped_column SELECT i,i,i,i FROM generate_series(1, 30) i; -GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO pathman_user2; +GRANT SELECT(val), INSERT(val) ON permissions.dropped_column TO regress_pathman_user2; SELECT create_range_partitions('permissions.dropped_column', 'val', 1, 10); @@ -168,10 +168,10 @@ DROP TABLE permissions.dropped_column CASCADE; /* Finally reset user */ RESET ROLE; -DROP OWNED BY pathman_user1; -DROP OWNED BY pathman_user2; -DROP USER pathman_user1; -DROP USER pathman_user2; +DROP OWNED BY regress_pathman_user1; +DROP OWNED BY regress_pathman_user2; +DROP USER regress_pathman_user1; +DROP USER regress_pathman_user2; DROP SCHEMA permissions; From 719c7ee985a7a6f9d538ce0b28ec22118c5378c3 Mon Sep 17 00:00:00 2001 From: Karina Litskevich Date: Wed, 24 Sep 2025 18:52:55 +0300 Subject: [PATCH 6/7] [PGPRO-14028] Update patches for v14, v15, v16 Tags: pg_pathman --- patches/REL_14_STABLE-pg_pathman-core.diff | 81 +++++++++++----------- patches/REL_15_STABLE-pg_pathman-core.diff | 77 ++++++++++---------- patches/REL_16_STABLE-pg_pathman-core.diff | 81 +++++++++++----------- 3 files changed, 124 insertions(+), 115 deletions(-) diff --git a/patches/REL_14_STABLE-pg_pathman-core.diff b/patches/REL_14_STABLE-pg_pathman-core.diff index a6ac1afa..c180a3bb 100644 --- a/patches/REL_14_STABLE-pg_pathman-core.diff +++ b/patches/REL_14_STABLE-pg_pathman-core.diff @@ -1,5 +1,5 @@ diff --git a/contrib/Makefile b/contrib/Makefile -index f27e458482..ea47c341c1 100644 +index f27e458482e..ea47c341c11 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -32,6 +32,7 @@ SUBDIRS = \ @@ -11,7 +11,7 @@ index f27e458482..ea47c341c1 100644 pg_stat_statements \ pg_surgery \ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c -index bf551b0395..10d2044ae6 100644 +index 3f0f711307d..a631b969e25 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -76,7 +76,7 @@ int DefaultXactIsoLevel = XACT_READ_COMMITTED; @@ -24,10 +24,10 @@ index bf551b0395..10d2044ae6 100644 bool DefaultXactDeferrable = false; bool XactDeferrable; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c -index bdf59a10fc..972453d9a5 100644 +index 4b31a85a24d..5366e67877a 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c -@@ -1799,6 +1799,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) +@@ -1811,6 +1811,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) } out: @@ -45,10 +45,10 @@ index bdf59a10fc..972453d9a5 100644 return state->resvalue; } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c -index b3ce4bae53..8f2bb12542 100644 +index 5d6410480cd..33a522514d9 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c -@@ -824,6 +824,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) +@@ -818,6 +818,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) estate->es_plannedstmt = plannedstmt; @@ -62,7 +62,7 @@ index b3ce4bae53..8f2bb12542 100644 /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. */ -@@ -2713,6 +2720,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) +@@ -2777,6 +2784,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) rcestate->es_junkFilter = parentestate->es_junkFilter; rcestate->es_output_cid = parentestate->es_output_cid; @@ -77,10 +77,10 @@ index b3ce4bae53..8f2bb12542 100644 * ResultRelInfos needed by subplans are initialized from scratch when the * subplans themselves are initialized. diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c -index 55c430c9ec..21d9e6304a 100644 +index ae1b07847b1..989ba4f7b11 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c -@@ -510,7 +510,7 @@ ExecInitInsertProjection(ModifyTableState *mtstate, +@@ -538,7 +538,7 @@ ExecInitInsertProjection(ModifyTableState *mtstate, * This is also a convenient place to verify that the output of an UPDATE * matches the target table (ExecBuildUpdateProjection does that). */ @@ -89,15 +89,15 @@ index 55c430c9ec..21d9e6304a 100644 ExecInitUpdateProjection(ModifyTableState *mtstate, ResultRelInfo *resultRelInfo) { -@@ -2486,6 +2486,7 @@ ExecModifyTable(PlanState *pstate) - ItemPointerData tuple_ctid; +@@ -2541,6 +2541,7 @@ ExecModifyTable(PlanState *pstate) HeapTupleData oldtupdata; HeapTuple oldtuple; + bool tuplock; + ResultRelInfo *saved_resultRelInfo; CHECK_FOR_INTERRUPTS(); -@@ -2523,12 +2524,23 @@ ExecModifyTable(PlanState *pstate) +@@ -2578,12 +2579,23 @@ ExecModifyTable(PlanState *pstate) resultRelInfo = node->resultRelInfo + node->mt_lastResultIndex; subplanstate = outerPlanState(node); @@ -121,7 +121,7 @@ index 55c430c9ec..21d9e6304a 100644 /* * Reset the per-output-tuple exprcontext. This is needed because * triggers expect to use that context as workspace. It's a bit ugly -@@ -2562,7 +2574,9 @@ ExecModifyTable(PlanState *pstate) +@@ -2617,7 +2629,9 @@ ExecModifyTable(PlanState *pstate) bool isNull; Oid resultoid; @@ -132,7 +132,7 @@ index 55c430c9ec..21d9e6304a 100644 &isNull); if (isNull) elog(ERROR, "tableoid is NULL"); -@@ -2581,6 +2595,8 @@ ExecModifyTable(PlanState *pstate) +@@ -2636,6 +2650,8 @@ ExecModifyTable(PlanState *pstate) if (resultRelInfo->ri_usesFdwDirectModify) { Assert(resultRelInfo->ri_projectReturning); @@ -141,7 +141,7 @@ index 55c430c9ec..21d9e6304a 100644 /* * A scan slot containing the data that was actually inserted, -@@ -2590,6 +2606,7 @@ ExecModifyTable(PlanState *pstate) +@@ -2645,6 +2661,7 @@ ExecModifyTable(PlanState *pstate) */ slot = ExecProcessReturning(resultRelInfo, NULL, planSlot); @@ -149,7 +149,7 @@ index 55c430c9ec..21d9e6304a 100644 return slot; } -@@ -2619,7 +2636,8 @@ ExecModifyTable(PlanState *pstate) +@@ -2674,7 +2691,8 @@ ExecModifyTable(PlanState *pstate) { /* ri_RowIdAttNo refers to a ctid attribute */ Assert(AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)); @@ -159,7 +159,7 @@ index 55c430c9ec..21d9e6304a 100644 resultRelInfo->ri_RowIdAttNo, &isNull); /* shouldn't ever get a null result... */ -@@ -2649,7 +2667,8 @@ ExecModifyTable(PlanState *pstate) +@@ -2704,7 +2722,8 @@ ExecModifyTable(PlanState *pstate) */ else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)) { @@ -169,7 +169,7 @@ index 55c430c9ec..21d9e6304a 100644 resultRelInfo->ri_RowIdAttNo, &isNull); /* shouldn't ever get a null result... */ -@@ -2680,8 +2699,12 @@ ExecModifyTable(PlanState *pstate) +@@ -2735,8 +2754,12 @@ ExecModifyTable(PlanState *pstate) /* Initialize projection info if first time for this table */ if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitInsertProjection(node, resultRelInfo); @@ -184,7 +184,7 @@ index 55c430c9ec..21d9e6304a 100644 estate, node->canSetTag); break; case CMD_UPDATE: -@@ -2689,6 +2712,13 @@ ExecModifyTable(PlanState *pstate) +@@ -2746,6 +2769,13 @@ ExecModifyTable(PlanState *pstate) if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitUpdateProjection(node, resultRelInfo); @@ -198,7 +198,7 @@ index 55c430c9ec..21d9e6304a 100644 /* * Make the new tuple by combining plan's output tuple with * the old tuple being updated. -@@ -2712,14 +2742,19 @@ ExecModifyTable(PlanState *pstate) +@@ -2775,9 +2805,12 @@ ExecModifyTable(PlanState *pstate) } slot = ExecGetUpdateNewTuple(resultRelInfo, planSlot, oldSlot); @@ -211,6 +211,9 @@ index 55c430c9ec..21d9e6304a 100644 + tupleid, oldtuple, slot, planSlot, &node->mt_epqstate, estate, node->canSetTag); + if (tuplock) +@@ -2785,7 +2818,9 @@ ExecModifyTable(PlanState *pstate) + InplaceUpdateTupleLock); break; case CMD_DELETE: - slot = ExecDelete(node, resultRelInfo, tupleid, oldtuple, @@ -220,7 +223,7 @@ index 55c430c9ec..21d9e6304a 100644 planSlot, &node->mt_epqstate, estate, true, /* processReturning */ node->canSetTag, -@@ -2736,7 +2771,10 @@ ExecModifyTable(PlanState *pstate) +@@ -2802,7 +2837,10 @@ ExecModifyTable(PlanState *pstate) * the work on next call. */ if (slot) @@ -231,7 +234,7 @@ index 55c430c9ec..21d9e6304a 100644 } /* -@@ -2752,6 +2790,7 @@ ExecModifyTable(PlanState *pstate) +@@ -2818,6 +2856,7 @@ ExecModifyTable(PlanState *pstate) node->mt_done = true; @@ -239,7 +242,7 @@ index 55c430c9ec..21d9e6304a 100644 return NULL; } -@@ -2826,6 +2865,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -2892,6 +2931,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ListCell *l; int i; Relation rel; @@ -247,7 +250,7 @@ index 55c430c9ec..21d9e6304a 100644 /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); -@@ -2922,6 +2962,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -2991,6 +3031,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) i++; } @@ -261,7 +264,7 @@ index 55c430c9ec..21d9e6304a 100644 /* * Now we may initialize the subplan. */ -@@ -3002,6 +3049,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -3071,6 +3118,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ExecInitStoredGenerated(resultRelInfo, estate, operation); } @@ -271,7 +274,7 @@ index 55c430c9ec..21d9e6304a 100644 * If this is an inherited update/delete, there will be a junk attribute * named "tableoid" present in the subplan's targetlist. It will be used diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c -index 381d9e548d..0a4657d291 100644 +index 381d9e548d1..0a4657d2915 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -25,7 +25,7 @@ @@ -284,7 +287,7 @@ index 381d9e548d..0a4657d291 100644 volatile sig_atomic_t InterruptPending = false; volatile sig_atomic_t QueryCancelPending = false; diff --git a/src/include/access/xact.h b/src/include/access/xact.h -index 5af78bd0dc..0c13bc9d83 100644 +index 5af78bd0dc7..0c13bc9d83b 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -53,7 +53,9 @@ extern PGDLLIMPORT int XactIsoLevel; @@ -299,7 +302,7 @@ index 5af78bd0dc..0c13bc9d83 100644 /* flag for logging statements in this transaction */ extern bool xact_is_sampled; diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h -index 2b4e104bb9..80d1274efe 100644 +index 3903e7a6f2e..49509a56c2d 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -28,7 +28,7 @@ typedef struct ObjectAddress @@ -312,10 +315,10 @@ index 2b4e104bb9..80d1274efe 100644 #define ObjectAddressSubSet(addr, class_id, object_id, object_sub_id) \ do { \ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h -index 3dc03c913e..1002d97499 100644 +index 4bb1744286a..af86e081918 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h -@@ -657,5 +657,7 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, +@@ -663,5 +663,7 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache); @@ -324,7 +327,7 @@ index 3dc03c913e..1002d97499 100644 #endif /* EXECUTOR_H */ diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h -index 4acb1cda6e..fd8d38347d 100644 +index 4acb1cda6ea..fd8d38347d3 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -327,7 +327,7 @@ extern ssize_t be_gssapi_read(Port *port, void *ptr, size_t len); @@ -337,10 +340,10 @@ index 4acb1cda6e..fd8d38347d 100644 /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h -index ee5ad3c058..dc474819d7 100644 +index 801d7630e9d..400814f0618 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h -@@ -592,6 +592,12 @@ typedef struct EState +@@ -593,6 +593,12 @@ typedef struct EState * es_result_relations in no * specific order */ @@ -354,7 +357,7 @@ index ee5ad3c058..dc474819d7 100644 /* diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h -index 33e6c14e81..abd9bba23e 100644 +index 33e6c14e819..abd9bba23e3 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -53,7 +53,7 @@ extern TimestampTz GetSnapshotCurrentTimestamp(void); @@ -367,7 +370,7 @@ index 33e6c14e81..abd9bba23e 100644 extern PGDLLIMPORT TransactionId TransactionXmin; extern PGDLLIMPORT TransactionId RecentXmin; diff --git a/src/tools/msvc/Install.pm b/src/tools/msvc/Install.pm -index de22c9ba2c..c8be5323b8 100644 +index de22c9ba2c7..c8be5323b8f 100644 --- a/src/tools/msvc/Install.pm +++ b/src/tools/msvc/Install.pm @@ -30,6 +30,18 @@ my @client_program_files = ( @@ -399,7 +402,7 @@ index de22c9ba2c..c8be5323b8 100644 sub CopyIncludeFiles diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm -index 9b6539fb15..f8a67c6701 100644 +index 43880a0a34c..ce7b8f7ac72 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -41,7 +41,10 @@ my @contrib_uselibpq = @@ -414,7 +417,7 @@ index 9b6539fb15..f8a67c6701 100644 my $contrib_extrasource = { 'cube' => [ 'contrib/cube/cubescan.l', 'contrib/cube/cubeparse.y' ], 'seg' => [ 'contrib/seg/segscan.l', 'contrib/seg/segparse.y' ], -@@ -973,6 +976,7 @@ sub AddContrib +@@ -977,6 +980,7 @@ sub AddContrib my $dn = $1; my $proj = $solution->AddProject($dn, 'dll', 'contrib', "$subdir/$n"); $proj->AddReference($postgres); @@ -422,7 +425,7 @@ index 9b6539fb15..f8a67c6701 100644 AdjustContribProj($proj); } elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg) -@@ -1002,6 +1006,19 @@ sub AddContrib +@@ -1006,6 +1010,19 @@ sub AddContrib return; } @@ -442,7 +445,7 @@ index 9b6539fb15..f8a67c6701 100644 sub GenerateContribSqlFiles { my $n = shift; -@@ -1026,23 +1043,53 @@ sub GenerateContribSqlFiles +@@ -1030,23 +1047,53 @@ sub GenerateContribSqlFiles substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1); } diff --git a/patches/REL_15_STABLE-pg_pathman-core.diff b/patches/REL_15_STABLE-pg_pathman-core.diff index b8db29fd..faafd713 100644 --- a/patches/REL_15_STABLE-pg_pathman-core.diff +++ b/patches/REL_15_STABLE-pg_pathman-core.diff @@ -1,5 +1,5 @@ diff --git a/contrib/Makefile b/contrib/Makefile -index bbf220407b..9a82a2db04 100644 +index bbf220407b0..9a82a2db046 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -34,6 +34,7 @@ SUBDIRS = \ @@ -11,7 +11,7 @@ index bbf220407b..9a82a2db04 100644 pg_stat_statements \ pg_surgery \ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c -index 7a3d9b4b01..0c3d2dec6c 100644 +index 7a3d9b4b012..0c3d2dec6c2 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -78,7 +78,7 @@ int DefaultXactIsoLevel = XACT_READ_COMMITTED; @@ -24,10 +24,10 @@ index 7a3d9b4b01..0c3d2dec6c 100644 bool DefaultXactDeferrable = false; bool XactDeferrable; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c -index 87c7603f2b..9cc0bc0da8 100644 +index 55d42cd101d..27c3fd507d0 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c -@@ -1801,6 +1801,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) +@@ -1813,6 +1813,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) } out: @@ -45,10 +45,10 @@ index 87c7603f2b..9cc0bc0da8 100644 return state->resvalue; } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c -index 0ba61fd547..29d93998b2 100644 +index ed4ff0246ce..dc2a5bf12a8 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c -@@ -826,6 +826,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) +@@ -820,6 +820,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) estate->es_plannedstmt = plannedstmt; @@ -62,7 +62,7 @@ index 0ba61fd547..29d93998b2 100644 /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. */ -@@ -2849,6 +2856,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) +@@ -2896,6 +2903,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) rcestate->es_junkFilter = parentestate->es_junkFilter; rcestate->es_output_cid = parentestate->es_output_cid; @@ -77,10 +77,10 @@ index 0ba61fd547..29d93998b2 100644 * ResultRelInfos needed by subplans are initialized from scratch when the * subplans themselves are initialized. diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c -index 1ad5dcb406..047508e0da 100644 +index 2cf118c90f0..2a8011854fa 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c -@@ -641,6 +641,13 @@ ExecInitUpdateProjection(ModifyTableState *mtstate, +@@ -670,6 +670,13 @@ ExecInitUpdateProjection(ModifyTableState *mtstate, resultRelInfo->ri_projectNewInfoValid = true; } @@ -94,15 +94,15 @@ index 1ad5dcb406..047508e0da 100644 /* * ExecGetInsertNewTuple * This prepares a "new" tuple ready to be inserted into given result -@@ -3581,6 +3588,7 @@ ExecModifyTable(PlanState *pstate) - HeapTupleData oldtupdata; +@@ -3750,6 +3757,7 @@ ExecModifyTable(PlanState *pstate) HeapTuple oldtuple; ItemPointer tupleid; + bool tuplock; + ResultRelInfo *saved_resultRelInfo; CHECK_FOR_INTERRUPTS(); -@@ -3622,6 +3630,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3791,6 +3799,8 @@ ExecModifyTable(PlanState *pstate) context.mtstate = node; context.epqstate = &node->mt_epqstate; context.estate = estate; @@ -111,7 +111,7 @@ index 1ad5dcb406..047508e0da 100644 /* * Fetch rows from subplan, and execute the required table modification -@@ -3629,6 +3639,14 @@ ExecModifyTable(PlanState *pstate) +@@ -3798,6 +3808,14 @@ ExecModifyTable(PlanState *pstate) */ for (;;) { @@ -126,7 +126,7 @@ index 1ad5dcb406..047508e0da 100644 /* * Reset the per-output-tuple exprcontext. This is needed because * triggers expect to use that context as workspace. It's a bit ugly -@@ -3662,7 +3680,9 @@ ExecModifyTable(PlanState *pstate) +@@ -3831,7 +3849,9 @@ ExecModifyTable(PlanState *pstate) bool isNull; Oid resultoid; @@ -137,7 +137,7 @@ index 1ad5dcb406..047508e0da 100644 &isNull); if (isNull) { -@@ -3699,6 +3719,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3868,6 +3888,8 @@ ExecModifyTable(PlanState *pstate) if (resultRelInfo->ri_usesFdwDirectModify) { Assert(resultRelInfo->ri_projectReturning); @@ -146,7 +146,7 @@ index 1ad5dcb406..047508e0da 100644 /* * A scan slot containing the data that was actually inserted, -@@ -3708,6 +3730,7 @@ ExecModifyTable(PlanState *pstate) +@@ -3877,6 +3899,7 @@ ExecModifyTable(PlanState *pstate) */ slot = ExecProcessReturning(resultRelInfo, NULL, context.planSlot); @@ -154,7 +154,7 @@ index 1ad5dcb406..047508e0da 100644 return slot; } -@@ -3738,7 +3761,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3907,7 +3930,8 @@ ExecModifyTable(PlanState *pstate) { /* ri_RowIdAttNo refers to a ctid attribute */ Assert(AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)); @@ -164,7 +164,7 @@ index 1ad5dcb406..047508e0da 100644 resultRelInfo->ri_RowIdAttNo, &isNull); -@@ -3786,7 +3810,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3955,7 +3979,8 @@ ExecModifyTable(PlanState *pstate) */ else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)) { @@ -174,7 +174,7 @@ index 1ad5dcb406..047508e0da 100644 resultRelInfo->ri_RowIdAttNo, &isNull); /* shouldn't ever get a null result... */ -@@ -3817,9 +3842,12 @@ ExecModifyTable(PlanState *pstate) +@@ -3986,9 +4011,12 @@ ExecModifyTable(PlanState *pstate) /* Initialize projection info if first time for this table */ if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitInsertProjection(node, resultRelInfo); @@ -190,7 +190,7 @@ index 1ad5dcb406..047508e0da 100644 break; case CMD_UPDATE: -@@ -3827,6 +3855,13 @@ ExecModifyTable(PlanState *pstate) +@@ -3998,6 +4026,13 @@ ExecModifyTable(PlanState *pstate) if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitUpdateProjection(node, resultRelInfo); @@ -204,7 +204,7 @@ index 1ad5dcb406..047508e0da 100644 /* * Make the new tuple by combining plan's output tuple with * the old tuple being updated. -@@ -3850,14 +3885,19 @@ ExecModifyTable(PlanState *pstate) +@@ -4027,9 +4062,12 @@ ExecModifyTable(PlanState *pstate) slot = ExecGetUpdateNewTuple(resultRelInfo, context.planSlot, oldSlot); context.relaction = NULL; @@ -216,6 +216,9 @@ index 1ad5dcb406..047508e0da 100644 + estate->es_result_relation_info : resultRelInfo, + tupleid, oldtuple, slot, node->canSetTag); + if (tuplock) + UnlockTuple(resultRelInfo->ri_RelationDesc, tupleid, +@@ -4037,7 +4075,9 @@ ExecModifyTable(PlanState *pstate) break; case CMD_DELETE: @@ -226,7 +229,7 @@ index 1ad5dcb406..047508e0da 100644 true, false, node->canSetTag, NULL, NULL, NULL); break; -@@ -3875,7 +3915,10 @@ ExecModifyTable(PlanState *pstate) +@@ -4055,7 +4095,10 @@ ExecModifyTable(PlanState *pstate) * the work on next call. */ if (slot) @@ -237,7 +240,7 @@ index 1ad5dcb406..047508e0da 100644 } /* -@@ -3891,6 +3934,7 @@ ExecModifyTable(PlanState *pstate) +@@ -4071,6 +4114,7 @@ ExecModifyTable(PlanState *pstate) node->mt_done = true; @@ -245,7 +248,7 @@ index 1ad5dcb406..047508e0da 100644 return NULL; } -@@ -3965,6 +4009,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4145,6 +4189,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ListCell *l; int i; Relation rel; @@ -253,7 +256,7 @@ index 1ad5dcb406..047508e0da 100644 /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); -@@ -4067,6 +4112,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4252,6 +4297,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) i++; } @@ -267,7 +270,7 @@ index 1ad5dcb406..047508e0da 100644 /* * Now we may initialize the subplan. */ -@@ -4161,6 +4213,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4346,6 +4398,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ExecInitStoredGenerated(resultRelInfo, estate, operation); } @@ -277,7 +280,7 @@ index 1ad5dcb406..047508e0da 100644 * If this is an inherited update/delete/merge, there will be a junk * attribute named "tableoid" present in the subplan's targetlist. It diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c -index 1a5d29ac9b..aadca8ea47 100644 +index 1a5d29ac9ba..aadca8ea474 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -25,7 +25,7 @@ @@ -290,7 +293,7 @@ index 1a5d29ac9b..aadca8ea47 100644 volatile sig_atomic_t InterruptPending = false; volatile sig_atomic_t QueryCancelPending = false; diff --git a/src/include/access/xact.h b/src/include/access/xact.h -index 8d46a781bb..150d70cb64 100644 +index 8d46a781bbd..150d70cb649 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -53,6 +53,8 @@ extern PGDLLIMPORT int XactIsoLevel; @@ -303,10 +306,10 @@ index 8d46a781bb..150d70cb64 100644 /* flag for logging statements in this transaction */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h -index 7cd9b2f2bf..b31a7934a4 100644 +index bce1aa6da39..982dfc1c596 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h -@@ -662,5 +662,17 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, +@@ -666,5 +666,17 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache); @@ -325,10 +328,10 @@ index 7cd9b2f2bf..b31a7934a4 100644 #endif /* EXECUTOR_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h -index 9f176b0e37..a65799dcce 100644 +index 8d831d0df6e..5b4ec77afaf 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h -@@ -624,6 +624,12 @@ typedef struct EState +@@ -626,6 +626,12 @@ typedef struct EState * es_result_relations in no * specific order */ @@ -342,7 +345,7 @@ index 9f176b0e37..a65799dcce 100644 /* diff --git a/src/tools/msvc/Install.pm b/src/tools/msvc/Install.pm -index 8de79c618c..c9226ba5ad 100644 +index 8de79c618cb..c9226ba5ad4 100644 --- a/src/tools/msvc/Install.pm +++ b/src/tools/msvc/Install.pm @@ -30,6 +30,18 @@ my @client_program_files = ( @@ -374,7 +377,7 @@ index 8de79c618c..c9226ba5ad 100644 sub CopyIncludeFiles diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm -index 990c223a9b..cd5048f8d5 100644 +index 3cbc8a83984..c44f033ab2c 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -39,8 +39,8 @@ my $contrib_defines = {}; @@ -388,7 +391,7 @@ index 990c223a9b..cd5048f8d5 100644 my $contrib_extrasource = {}; my @contrib_excludes = ( 'bool_plperl', 'commit_ts', -@@ -967,6 +967,7 @@ sub AddContrib +@@ -969,6 +969,7 @@ sub AddContrib my $dn = $1; my $proj = $solution->AddProject($dn, 'dll', 'contrib', "$subdir/$n"); $proj->AddReference($postgres); @@ -396,7 +399,7 @@ index 990c223a9b..cd5048f8d5 100644 AdjustContribProj($proj); push @projects, $proj; } -@@ -1070,6 +1071,19 @@ sub AddContrib +@@ -1072,6 +1073,19 @@ sub AddContrib return; } @@ -416,7 +419,7 @@ index 990c223a9b..cd5048f8d5 100644 sub GenerateContribSqlFiles { my $n = shift; -@@ -1094,23 +1108,53 @@ sub GenerateContribSqlFiles +@@ -1096,23 +1110,53 @@ sub GenerateContribSqlFiles substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1); } diff --git a/patches/REL_16_STABLE-pg_pathman-core.diff b/patches/REL_16_STABLE-pg_pathman-core.diff index 50dad389..0a422864 100644 --- a/patches/REL_16_STABLE-pg_pathman-core.diff +++ b/patches/REL_16_STABLE-pg_pathman-core.diff @@ -1,5 +1,5 @@ diff --git a/contrib/Makefile b/contrib/Makefile -index bbf220407b..9a82a2db04 100644 +index bbf220407b0..9a82a2db046 100644 --- a/contrib/Makefile +++ b/contrib/Makefile @@ -34,6 +34,7 @@ SUBDIRS = \ @@ -11,7 +11,7 @@ index bbf220407b..9a82a2db04 100644 pg_stat_statements \ pg_surgery \ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c -index 4a2ea4adba..7cadde5499 100644 +index 4a2ea4adbaf..7cadde5499b 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -79,7 +79,7 @@ int DefaultXactIsoLevel = XACT_READ_COMMITTED; @@ -24,10 +24,10 @@ index 4a2ea4adba..7cadde5499 100644 bool DefaultXactDeferrable = false; bool XactDeferrable; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c -index 6b7997465d..5e9e878d3b 100644 +index 30ea9627c75..8aca4d3a86b 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c -@@ -1845,6 +1845,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) +@@ -1857,6 +1857,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) } out: @@ -45,10 +45,10 @@ index 6b7997465d..5e9e878d3b 100644 return state->resvalue; } diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c -index 4c5a7bbf62..7d638aa22d 100644 +index 7ec4d14f66b..52952ed3dd8 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c -@@ -561,6 +561,39 @@ ExecutorRewind(QueryDesc *queryDesc) +@@ -554,6 +554,39 @@ ExecutorRewind(QueryDesc *queryDesc) } @@ -88,7 +88,7 @@ index 4c5a7bbf62..7d638aa22d 100644 /* * ExecCheckPermissions * Check access permissions of relations mentioned in a query -@@ -856,6 +889,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) +@@ -849,6 +882,13 @@ InitPlan(QueryDesc *queryDesc, int eflags) estate->es_plannedstmt = plannedstmt; @@ -102,7 +102,7 @@ index 4c5a7bbf62..7d638aa22d 100644 /* * Next, build the ExecRowMark array from the PlanRowMark(s), if any. */ -@@ -2873,6 +2913,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) +@@ -2919,6 +2959,13 @@ EvalPlanQualStart(EPQState *epqstate, Plan *planTree) rcestate->es_output_cid = parentestate->es_output_cid; rcestate->es_queryEnv = parentestate->es_queryEnv; @@ -117,10 +117,10 @@ index 4c5a7bbf62..7d638aa22d 100644 * ResultRelInfos needed by subplans are initialized from scratch when the * subplans themselves are initialized. diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c -index c84caeeaee..2a355607e9 100644 +index 6597356c018..aaabca83e48 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c -@@ -660,6 +660,13 @@ ExecInitUpdateProjection(ModifyTableState *mtstate, +@@ -689,6 +689,13 @@ ExecInitUpdateProjection(ModifyTableState *mtstate, resultRelInfo->ri_projectNewInfoValid = true; } @@ -134,15 +134,15 @@ index c84caeeaee..2a355607e9 100644 /* * ExecGetInsertNewTuple * This prepares a "new" tuple ready to be inserted into given result -@@ -3570,6 +3577,7 @@ ExecModifyTable(PlanState *pstate) - HeapTupleData oldtupdata; +@@ -3770,6 +3777,7 @@ ExecModifyTable(PlanState *pstate) HeapTuple oldtuple; ItemPointer tupleid; + bool tuplock; + ResultRelInfo *saved_resultRelInfo; CHECK_FOR_INTERRUPTS(); -@@ -3611,6 +3619,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3811,6 +3819,8 @@ ExecModifyTable(PlanState *pstate) context.mtstate = node; context.epqstate = &node->mt_epqstate; context.estate = estate; @@ -151,7 +151,7 @@ index c84caeeaee..2a355607e9 100644 /* * Fetch rows from subplan, and execute the required table modification -@@ -3618,6 +3628,14 @@ ExecModifyTable(PlanState *pstate) +@@ -3818,6 +3828,14 @@ ExecModifyTable(PlanState *pstate) */ for (;;) { @@ -166,7 +166,7 @@ index c84caeeaee..2a355607e9 100644 /* * Reset the per-output-tuple exprcontext. This is needed because * triggers expect to use that context as workspace. It's a bit ugly -@@ -3651,7 +3669,9 @@ ExecModifyTable(PlanState *pstate) +@@ -3851,7 +3869,9 @@ ExecModifyTable(PlanState *pstate) bool isNull; Oid resultoid; @@ -177,7 +177,7 @@ index c84caeeaee..2a355607e9 100644 &isNull); if (isNull) { -@@ -3688,6 +3708,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3888,6 +3908,8 @@ ExecModifyTable(PlanState *pstate) if (resultRelInfo->ri_usesFdwDirectModify) { Assert(resultRelInfo->ri_projectReturning); @@ -186,7 +186,7 @@ index c84caeeaee..2a355607e9 100644 /* * A scan slot containing the data that was actually inserted, -@@ -3697,6 +3719,7 @@ ExecModifyTable(PlanState *pstate) +@@ -3897,6 +3919,7 @@ ExecModifyTable(PlanState *pstate) */ slot = ExecProcessReturning(resultRelInfo, NULL, context.planSlot); @@ -194,7 +194,7 @@ index c84caeeaee..2a355607e9 100644 return slot; } -@@ -3727,7 +3750,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3927,7 +3950,8 @@ ExecModifyTable(PlanState *pstate) { /* ri_RowIdAttNo refers to a ctid attribute */ Assert(AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)); @@ -204,7 +204,7 @@ index c84caeeaee..2a355607e9 100644 resultRelInfo->ri_RowIdAttNo, &isNull); -@@ -3775,7 +3799,8 @@ ExecModifyTable(PlanState *pstate) +@@ -3975,7 +3999,8 @@ ExecModifyTable(PlanState *pstate) */ else if (AttributeNumberIsValid(resultRelInfo->ri_RowIdAttNo)) { @@ -214,7 +214,7 @@ index c84caeeaee..2a355607e9 100644 resultRelInfo->ri_RowIdAttNo, &isNull); /* shouldn't ever get a null result... */ -@@ -3806,9 +3831,12 @@ ExecModifyTable(PlanState *pstate) +@@ -4006,9 +4031,12 @@ ExecModifyTable(PlanState *pstate) /* Initialize projection info if first time for this table */ if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitInsertProjection(node, resultRelInfo); @@ -230,7 +230,7 @@ index c84caeeaee..2a355607e9 100644 break; case CMD_UPDATE: -@@ -3816,6 +3844,13 @@ ExecModifyTable(PlanState *pstate) +@@ -4018,6 +4046,13 @@ ExecModifyTable(PlanState *pstate) if (unlikely(!resultRelInfo->ri_projectNewInfoValid)) ExecInitUpdateProjection(node, resultRelInfo); @@ -244,7 +244,7 @@ index c84caeeaee..2a355607e9 100644 /* * Make the new tuple by combining plan's output tuple with * the old tuple being updated. -@@ -3839,14 +3874,19 @@ ExecModifyTable(PlanState *pstate) +@@ -4047,9 +4082,12 @@ ExecModifyTable(PlanState *pstate) slot = ExecGetUpdateNewTuple(resultRelInfo, context.planSlot, oldSlot); context.relaction = NULL; @@ -256,6 +256,9 @@ index c84caeeaee..2a355607e9 100644 + estate->es_result_relation_info : resultRelInfo, + tupleid, oldtuple, slot, node->canSetTag); + if (tuplock) + UnlockTuple(resultRelInfo->ri_RelationDesc, tupleid, +@@ -4057,7 +4095,9 @@ ExecModifyTable(PlanState *pstate) break; case CMD_DELETE: @@ -266,7 +269,7 @@ index c84caeeaee..2a355607e9 100644 true, false, node->canSetTag, NULL, NULL, NULL); break; -@@ -3864,7 +3904,10 @@ ExecModifyTable(PlanState *pstate) +@@ -4075,7 +4115,10 @@ ExecModifyTable(PlanState *pstate) * the work on next call. */ if (slot) @@ -277,7 +280,7 @@ index c84caeeaee..2a355607e9 100644 } /* -@@ -3880,6 +3923,7 @@ ExecModifyTable(PlanState *pstate) +@@ -4091,6 +4134,7 @@ ExecModifyTable(PlanState *pstate) node->mt_done = true; @@ -285,7 +288,7 @@ index c84caeeaee..2a355607e9 100644 return NULL; } -@@ -3954,6 +3998,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4165,6 +4209,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ListCell *l; int i; Relation rel; @@ -293,7 +296,7 @@ index c84caeeaee..2a355607e9 100644 /* check for unsupported flags */ Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK))); -@@ -4056,6 +4101,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4272,6 +4317,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) i++; } @@ -307,7 +310,7 @@ index c84caeeaee..2a355607e9 100644 /* * Now we may initialize the subplan. */ -@@ -4138,6 +4190,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) +@@ -4354,6 +4406,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) } } @@ -317,7 +320,7 @@ index c84caeeaee..2a355607e9 100644 * If this is an inherited update/delete/merge, there will be a junk * attribute named "tableoid" present in the subplan's targetlist. It diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c -index 011ec18015..7b4fcb2807 100644 +index 011ec18015a..7b4fcb2807c 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -25,7 +25,7 @@ @@ -330,7 +333,7 @@ index 011ec18015..7b4fcb2807 100644 volatile sig_atomic_t InterruptPending = false; volatile sig_atomic_t QueryCancelPending = false; diff --git a/src/include/access/xact.h b/src/include/access/xact.h -index 7d3b9446e6..20030111f4 100644 +index 7d3b9446e62..20030111f4d 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -53,6 +53,8 @@ extern PGDLLIMPORT int XactIsoLevel; @@ -343,7 +346,7 @@ index 7d3b9446e6..20030111f4 100644 /* flag for logging statements in this transaction */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h -index ac02247947..c39ae13a8e 100644 +index baef7e031ee..d1ad369dac5 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -208,6 +208,9 @@ extern void standard_ExecutorFinish(QueryDesc *queryDesc); @@ -355,8 +358,8 @@ index ac02247947..c39ae13a8e 100644 + bool ereport_on_violation); extern bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation); - extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation); -@@ -676,5 +679,17 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, + extern bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo); +@@ -680,5 +683,17 @@ extern ResultRelInfo *ExecLookupResultRelByOid(ModifyTableState *node, Oid resultoid, bool missing_ok, bool update_cache); @@ -375,10 +378,10 @@ index ac02247947..c39ae13a8e 100644 #endif /* EXECUTOR_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h -index 869465d6f8..6bdde351d7 100644 +index 74718fa256d..a524e7310c6 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h -@@ -638,6 +638,12 @@ typedef struct EState +@@ -640,6 +640,12 @@ typedef struct EState * es_result_relations in no * specific order */ @@ -392,7 +395,7 @@ index 869465d6f8..6bdde351d7 100644 /* diff --git a/src/tools/msvc/Install.pm b/src/tools/msvc/Install.pm -index 05548d7c0a..37754370e0 100644 +index 05548d7c0aa..37754370e0c 100644 --- a/src/tools/msvc/Install.pm +++ b/src/tools/msvc/Install.pm @@ -30,6 +30,22 @@ my @client_program_files = ( @@ -428,7 +431,7 @@ index 05548d7c0a..37754370e0 100644 sub CopyIncludeFiles diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm -index 6a79a0e037..93696f53ae 100644 +index e224f8d7480..4cfe9cf9d93 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -40,7 +40,7 @@ my @contrib_uselibpq = (); @@ -440,7 +443,7 @@ index 6a79a0e037..93696f53ae 100644 my $contrib_extrasource = {}; my @contrib_excludes = ( 'bool_plperl', 'commit_ts', -@@ -980,6 +980,7 @@ sub AddContrib +@@ -981,6 +981,7 @@ sub AddContrib my $dn = $1; my $proj = $solution->AddProject($dn, 'dll', 'contrib', "$subdir/$n"); $proj->AddReference($postgres); @@ -448,7 +451,7 @@ index 6a79a0e037..93696f53ae 100644 AdjustContribProj($proj); push @projects, $proj; } -@@ -1083,6 +1084,22 @@ sub AddContrib +@@ -1084,6 +1085,22 @@ sub AddContrib return; } @@ -471,7 +474,7 @@ index 6a79a0e037..93696f53ae 100644 sub GenerateContribSqlFiles { my $n = shift; -@@ -1107,23 +1124,59 @@ sub GenerateContribSqlFiles +@@ -1108,23 +1125,59 @@ sub GenerateContribSqlFiles substr($l, 0, index($l, '$(addsuffix ')) . substr($l, $i + 1); } From 7898a903e88b8f19fc3ebaec9f76a28c90e09ca3 Mon Sep 17 00:00:00 2001 From: Karina Litskevich Date: Thu, 25 Sep 2025 13:32:38 +0300 Subject: [PATCH 7/7] [PGPRO-14028] Add clang19 to Travis CI configuration for PostgreSQL 13 Tags: pg_pathman --- Dockerfile.tmpl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile.tmpl b/Dockerfile.tmpl index 4dd24ca5..ffb67d95 100644 --- a/Dockerfile.tmpl +++ b/Dockerfile.tmpl @@ -11,6 +11,9 @@ RUN apk add --no-cache \ zlib-dev libedit-dev \ pkgconf icu-dev clang clang15 clang-analyzer; +# Need this for Travis CI to pass +RUN if [ "${PG_VERSION}" == "13" ] ; then apk add --no-cache clang19; fi + # Install fresh valgrind RUN apk add valgrind \ --update-cache \