From 6bcd9d82b91baffd6b7024501e7c1837ddaffb1e Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Fri, 10 Mar 2023 19:58:11 +0300 Subject: [PATCH 1/2] [PGPRO-7880] Need to check relation Oid before locking It need to do before relation locking: locking of invalid Oid causes an error on replica Tags: pg_pathman --- expected/pathman_calamity.out | 10 +++++----- expected/pathman_calamity_1.out | 10 +++++----- expected/pathman_calamity_2.out | 10 +++++----- expected/pathman_calamity_3.out | 10 +++++----- src/include/utils.h | 1 + src/pathman_workers.c | 2 ++ src/pl_funcs.c | 6 ++++++ src/pl_range_funcs.c | 3 +++ src/utils.c | 11 +++++++++++ 9 files changed, 43 insertions(+), 20 deletions(-) diff --git a/expected/pathman_calamity.out b/expected/pathman_calamity.out index 7226e7b9..b9421bde 100644 --- a/expected/pathman_calamity.out +++ b/expected/pathman_calamity.out @@ -320,7 +320,7 @@ SELECT validate_relname(NULL); ERROR: relation should not be NULL /* check function validate_expression() */ SELECT validate_expression(1::regclass, NULL); /* not ok */ -ERROR: relation "1" does not exist +ERROR: identifier "1" must be normal Oid SELECT validate_expression(NULL::regclass, NULL); /* not ok */ ERROR: 'relid' should not be NULL SELECT validate_expression('calamity.part_test', NULL); /* not ok */ @@ -426,19 +426,19 @@ SELECT build_sequence_name(NULL) IS NULL; /* check function partition_table_concurrently() */ SELECT partition_table_concurrently(1::REGCLASS); /* not ok */ -ERROR: relation "1" has no partitions +ERROR: identifier "1" must be normal Oid SELECT partition_table_concurrently('pg_class', 0); /* not ok */ ERROR: 'batch_size' should not be less than 1 or greater than 10000 SELECT partition_table_concurrently('pg_class', 1, 1E-5); /* not ok */ ERROR: 'sleep_time' should not be less than 0.5 SELECT partition_table_concurrently('pg_class'); /* not ok */ -ERROR: relation "pg_class" has no partitions +ERROR: identifier "1259" must be normal Oid /* check function stop_concurrent_part_task() */ SELECT stop_concurrent_part_task(1::REGCLASS); /* not ok */ ERROR: cannot find worker for relation "1" /* check function drop_range_partition_expand_next() */ SELECT drop_range_partition_expand_next('pg_class'); /* not ok */ -ERROR: relation "pg_class" is not a partition +ERROR: identifier "1259" must be normal Oid SELECT drop_range_partition_expand_next(NULL) IS NULL; ?column? ---------- @@ -560,7 +560,7 @@ DROP FUNCTION calamity.dummy_cb(arg jsonb); SELECT add_to_pathman_config(NULL, 'val'); /* no table */ ERROR: 'parent_relid' should not be NULL SELECT add_to_pathman_config(0::REGCLASS, 'val'); /* no table (oid) */ -ERROR: relation "0" does not exist +ERROR: identifier "0" must be normal Oid SELECT add_to_pathman_config('calamity.part_test', NULL); /* no expr */ ERROR: 'expression' should not be NULL SELECT add_to_pathman_config('calamity.part_test', 'V_A_L'); /* wrong expr */ diff --git a/expected/pathman_calamity_1.out b/expected/pathman_calamity_1.out index 62050cfd..6ca2e7dd 100644 --- a/expected/pathman_calamity_1.out +++ b/expected/pathman_calamity_1.out @@ -320,7 +320,7 @@ SELECT validate_relname(NULL); ERROR: relation should not be NULL /* check function validate_expression() */ SELECT validate_expression(1::regclass, NULL); /* not ok */ -ERROR: relation "1" does not exist +ERROR: identifier "1" must be normal Oid SELECT validate_expression(NULL::regclass, NULL); /* not ok */ ERROR: 'relid' should not be NULL SELECT validate_expression('calamity.part_test', NULL); /* not ok */ @@ -426,19 +426,19 @@ SELECT build_sequence_name(NULL) IS NULL; /* check function partition_table_concurrently() */ SELECT partition_table_concurrently(1::REGCLASS); /* not ok */ -ERROR: relation "1" has no partitions +ERROR: identifier "1" must be normal Oid SELECT partition_table_concurrently('pg_class', 0); /* not ok */ ERROR: 'batch_size' should not be less than 1 or greater than 10000 SELECT partition_table_concurrently('pg_class', 1, 1E-5); /* not ok */ ERROR: 'sleep_time' should not be less than 0.5 SELECT partition_table_concurrently('pg_class'); /* not ok */ -ERROR: relation "pg_class" has no partitions +ERROR: identifier "1259" must be normal Oid /* check function stop_concurrent_part_task() */ SELECT stop_concurrent_part_task(1::REGCLASS); /* not ok */ ERROR: cannot find worker for relation "1" /* check function drop_range_partition_expand_next() */ SELECT drop_range_partition_expand_next('pg_class'); /* not ok */ -ERROR: relation "pg_class" is not a partition +ERROR: identifier "1259" must be normal Oid SELECT drop_range_partition_expand_next(NULL) IS NULL; ?column? ---------- @@ -560,7 +560,7 @@ DROP FUNCTION calamity.dummy_cb(arg jsonb); SELECT add_to_pathman_config(NULL, 'val'); /* no table */ ERROR: 'parent_relid' should not be NULL SELECT add_to_pathman_config(0::REGCLASS, 'val'); /* no table (oid) */ -ERROR: relation "0" does not exist +ERROR: identifier "0" must be normal Oid SELECT add_to_pathman_config('calamity.part_test', NULL); /* no expr */ ERROR: 'expression' should not be NULL SELECT add_to_pathman_config('calamity.part_test', 'V_A_L'); /* wrong expr */ diff --git a/expected/pathman_calamity_2.out b/expected/pathman_calamity_2.out index 5bb1053f..fa3295f6 100644 --- a/expected/pathman_calamity_2.out +++ b/expected/pathman_calamity_2.out @@ -320,7 +320,7 @@ SELECT validate_relname(NULL); ERROR: relation should not be NULL /* check function validate_expression() */ SELECT validate_expression(1::regclass, NULL); /* not ok */ -ERROR: relation "1" does not exist +ERROR: identifier "1" must be normal Oid SELECT validate_expression(NULL::regclass, NULL); /* not ok */ ERROR: 'relid' should not be NULL SELECT validate_expression('calamity.part_test', NULL); /* not ok */ @@ -426,19 +426,19 @@ SELECT build_sequence_name(NULL) IS NULL; /* check function partition_table_concurrently() */ SELECT partition_table_concurrently(1::REGCLASS); /* not ok */ -ERROR: relation "1" has no partitions +ERROR: identifier "1" must be normal Oid SELECT partition_table_concurrently('pg_class', 0); /* not ok */ ERROR: 'batch_size' should not be less than 1 or greater than 10000 SELECT partition_table_concurrently('pg_class', 1, 1E-5); /* not ok */ ERROR: 'sleep_time' should not be less than 0.5 SELECT partition_table_concurrently('pg_class'); /* not ok */ -ERROR: relation "pg_class" has no partitions +ERROR: identifier "1259" must be normal Oid /* check function stop_concurrent_part_task() */ SELECT stop_concurrent_part_task(1::REGCLASS); /* not ok */ ERROR: cannot find worker for relation "1" /* check function drop_range_partition_expand_next() */ SELECT drop_range_partition_expand_next('pg_class'); /* not ok */ -ERROR: relation "pg_class" is not a partition +ERROR: identifier "1259" must be normal Oid SELECT drop_range_partition_expand_next(NULL) IS NULL; ?column? ---------- @@ -560,7 +560,7 @@ DROP FUNCTION calamity.dummy_cb(arg jsonb); SELECT add_to_pathman_config(NULL, 'val'); /* no table */ ERROR: 'parent_relid' should not be NULL SELECT add_to_pathman_config(0::REGCLASS, 'val'); /* no table (oid) */ -ERROR: relation "0" does not exist +ERROR: identifier "0" must be normal Oid SELECT add_to_pathman_config('calamity.part_test', NULL); /* no expr */ ERROR: 'expression' should not be NULL SELECT add_to_pathman_config('calamity.part_test', 'V_A_L'); /* wrong expr */ diff --git a/expected/pathman_calamity_3.out b/expected/pathman_calamity_3.out index bfb3b63c..a8879ef7 100644 --- a/expected/pathman_calamity_3.out +++ b/expected/pathman_calamity_3.out @@ -324,7 +324,7 @@ SELECT validate_relname(NULL); ERROR: relation should not be NULL /* check function validate_expression() */ SELECT validate_expression(1::regclass, NULL); /* not ok */ -ERROR: relation "1" does not exist +ERROR: identifier "1" must be normal Oid SELECT validate_expression(NULL::regclass, NULL); /* not ok */ ERROR: 'relid' should not be NULL SELECT validate_expression('calamity.part_test', NULL); /* not ok */ @@ -430,19 +430,19 @@ SELECT build_sequence_name(NULL) IS NULL; /* check function partition_table_concurrently() */ SELECT partition_table_concurrently(1::REGCLASS); /* not ok */ -ERROR: relation "1" has no partitions +ERROR: identifier "1" must be normal Oid SELECT partition_table_concurrently('pg_class', 0); /* not ok */ ERROR: 'batch_size' should not be less than 1 or greater than 10000 SELECT partition_table_concurrently('pg_class', 1, 1E-5); /* not ok */ ERROR: 'sleep_time' should not be less than 0.5 SELECT partition_table_concurrently('pg_class'); /* not ok */ -ERROR: relation "pg_class" has no partitions +ERROR: identifier "1259" must be normal Oid /* check function stop_concurrent_part_task() */ SELECT stop_concurrent_part_task(1::REGCLASS); /* not ok */ ERROR: cannot find worker for relation "1" /* check function drop_range_partition_expand_next() */ SELECT drop_range_partition_expand_next('pg_class'); /* not ok */ -ERROR: relation "pg_class" is not a partition +ERROR: identifier "1259" must be normal Oid SELECT drop_range_partition_expand_next(NULL) IS NULL; ?column? ---------- @@ -564,7 +564,7 @@ DROP FUNCTION calamity.dummy_cb(arg jsonb); SELECT add_to_pathman_config(NULL, 'val'); /* no table */ ERROR: 'parent_relid' should not be NULL SELECT add_to_pathman_config(0::REGCLASS, 'val'); /* no table (oid) */ -ERROR: relation "0" does not exist +ERROR: identifier "0" must be normal Oid SELECT add_to_pathman_config('calamity.part_test', NULL); /* no expr */ ERROR: 'expression' should not be NULL SELECT add_to_pathman_config('calamity.part_test', 'V_A_L'); /* wrong expr */ diff --git a/src/include/utils.h b/src/include/utils.h index 1e0b87a4..566c04db 100644 --- a/src/include/utils.h +++ b/src/include/utils.h @@ -84,5 +84,6 @@ Datum extract_binary_interval_from_text(Datum interval_text, Oid *interval_type); char **deconstruct_text_array(Datum array, int *array_size); RangeVar **qualified_relnames_to_rangevars(char **relnames, size_t nrelnames); +void check_relation_oid(Oid relid); #endif /* PATHMAN_UTILS_H */ diff --git a/src/pathman_workers.c b/src/pathman_workers.c index eca9ee52..3eb82ab7 100644 --- a/src/pathman_workers.c +++ b/src/pathman_workers.c @@ -712,6 +712,8 @@ partition_table_concurrently(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("'sleep_time' should not be less than 0.5"))); + check_relation_oid(relid); + /* Prevent concurrent function calls */ LockRelationOid(relid, lockmode); diff --git a/src/pl_funcs.c b/src/pl_funcs.c index 542f99ae..10538bea 100644 --- a/src/pl_funcs.c +++ b/src/pl_funcs.c @@ -673,6 +673,7 @@ validate_expression(PG_FUNCTION_ARGS) if (!PG_ARGISNULL(0)) { relid = PG_GETARG_OID(0); + check_relation_oid(relid); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("'relid' should not be NULL"))); @@ -807,6 +808,7 @@ add_to_pathman_config(PG_FUNCTION_ARGS) if (!PG_ARGISNULL(0)) { relid = PG_GETARG_OID(0); + check_relation_oid(relid); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("'parent_relid' should not be NULL"))); @@ -1037,6 +1039,8 @@ prevent_part_modification(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); + check_relation_oid(relid); + /* Lock partitioned relation till transaction's end */ LockRelationOid(relid, ShareUpdateExclusiveLock); @@ -1051,6 +1055,8 @@ prevent_data_modification(PG_FUNCTION_ARGS) { Oid relid = PG_GETARG_OID(0); + check_relation_oid(relid); + /* * Check that isolation level is READ COMMITTED. * Else we won't be able to see new rows diff --git a/src/pl_range_funcs.c b/src/pl_range_funcs.c index b2a8dc3d..19292a0a 100644 --- a/src/pl_range_funcs.c +++ b/src/pl_range_funcs.c @@ -499,6 +499,7 @@ split_range_partition(PG_FUNCTION_ARGS) if (!PG_ARGISNULL(0)) { partition1 = PG_GETARG_OID(0); + check_relation_oid(partition1); } else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("'partition1' should not be NULL"))); @@ -835,6 +836,8 @@ drop_range_partition_expand_next(PG_FUNCTION_ARGS) RangeEntry *ranges; int i; + check_relation_oid(partition); + /* Lock the partition we're going to drop */ LockRelationOid(partition, AccessExclusiveLock); diff --git a/src/utils.c b/src/utils.c index 6ebfb8a8..9402d618 100644 --- a/src/utils.c +++ b/src/utils.c @@ -527,3 +527,14 @@ qualified_relnames_to_rangevars(char **relnames, size_t nrelnames) return rangevars; } +/* + * Checks that Oid is valid (it need to do before relation locking: locking of + * invalid Oid causes an error on replica). + */ +void +check_relation_oid(Oid relid) +{ + if (relid < FirstNormalObjectId) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("identifier \"%u\" must be normal Oid", relid))); +} From 47acbe67e07bbf5841e52b705bdb03aa1adf768e Mon Sep 17 00:00:00 2001 From: Koval Dmitry Date: Thu, 9 Mar 2023 21:29:56 +0300 Subject: [PATCH 2/2] [PGPRO-7870] Added error for case executing prepared query after DROP/CREATE EXTENSION Tags: pg_pathman --- expected/pathman_cache_pranks.out | 150 ++++++++++++++++++ expected/pathman_cache_pranks_1.out | 237 ++++++++++++++++++++++++++++ sql/pathman_cache_pranks.sql | 69 ++++++++ src/nodes_common.c | 15 +- 4 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 expected/pathman_cache_pranks_1.out diff --git a/expected/pathman_cache_pranks.out b/expected/pathman_cache_pranks.out index 5493ae96..278643ff 100644 --- a/expected/pathman_cache_pranks.out +++ b/expected/pathman_cache_pranks.out @@ -76,5 +76,155 @@ ERROR: can't partition table "part_test" with existing children DROP TABLE part_test CASCADE; NOTICE: drop cascades to 302 other objects -- +-- +-- PGPRO-7870 +-- Added error for case executing prepared query after DROP/CREATE EXTENSION. +-- +-- DROP/CREATE extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + create_range_partitions +------------------------- + 10 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +EXECUTE q(1); +ERROR: table "part_test" is not partitioned +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 11 other objects +-- DROP/CREATE disabled extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + create_range_partitions +------------------------- + 10 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +SET pg_pathman.enable = f; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been disabled +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +SET pg_pathman.enable = t; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been enabled +EXECUTE q(1); +ERROR: table "part_test" is not partitioned +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 11 other objects +-- DROP/CREATE extension in autonomous transaction +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 198]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 2); + create_range_partitions +------------------------- + 2 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +BEGIN; + BEGIN AUTONOMOUS; + DROP EXTENSION pg_pathman; + CREATE EXTENSION pg_pathman; + COMMIT; +COMMIT; +EXECUTE q(1); +ERROR: table "part_test" is not partitioned +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 3 other objects -- finalize DROP EXTENSION pg_pathman; diff --git a/expected/pathman_cache_pranks_1.out b/expected/pathman_cache_pranks_1.out new file mode 100644 index 00000000..4a3982a6 --- /dev/null +++ b/expected/pathman_cache_pranks_1.out @@ -0,0 +1,237 @@ +\set VERBOSITY terse +-- is pathman (caches, in particular) strong enough to carry out this? +SET search_path = 'public'; +-- make sure nothing breaks on disable/enable when nothing was initialized yet +SET pg_pathman.enable = false; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been disabled +SET pg_pathman.enable = true; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been enabled +-- wobble with create-drop ext: tests cached relids sanity +CREATE EXTENSION pg_pathman; +SET pg_pathman.enable = f; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been disabled +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +SET pg_pathman.enable = true; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been enabled +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +DROP EXTENSION pg_pathman; +-- create it for further tests +CREATE EXTENSION pg_pathman; +-- 079797e0d5 +CREATE TABLE part_test(val serial); +INSERT INTO part_test SELECT generate_series(1, 30); +SELECT create_range_partitions('part_test', 'val', 1, 10); + create_range_partitions +------------------------- + 3 +(1 row) + +SELECT set_interval('part_test', 100); + set_interval +-------------- + +(1 row) + +DELETE FROM pathman_config WHERE partrel = 'part_test'::REGCLASS; +SELECT drop_partitions('part_test'); +ERROR: table "part_test" has no partitions +SELECT disable_pathman_for('part_test'); + disable_pathman_for +--------------------- + +(1 row) + +CREATE TABLE wrong_partition (LIKE part_test) INHERITS (part_test); +NOTICE: merging column "val" with inherited definition +SELECT add_to_pathman_config('part_test', 'val', '10'); +ERROR: constraint "pathman_wrong_partition_check" of partition "wrong_partition" does not exist +SELECT add_to_pathman_config('part_test', 'val'); +ERROR: wrong constraint format for HASH partition "part_test_1" +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 5 other objects +-- +-- 85fc5ccf121 +CREATE TABLE part_test(val serial); +INSERT INTO part_test SELECT generate_series(1, 3000); +SELECT create_range_partitions('part_test', 'val', 1, 10); + create_range_partitions +------------------------- + 300 +(1 row) + +SELECT append_range_partition('part_test'); + append_range_partition +------------------------ + part_test_301 +(1 row) + +DELETE FROM part_test; +SELECT create_single_range_partition('part_test', NULL::INT4, NULL); /* not ok */ +ERROR: cannot create partition with range (-inf, +inf) +DELETE FROM pathman_config WHERE partrel = 'part_test'::REGCLASS; +SELECT create_hash_partitions('part_test', 'val', 2, partition_names := ARRAY[]::TEXT[]); /* not ok */ +ERROR: can't partition table "part_test" with existing children +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 302 other objects +-- +-- +-- PGPRO-7870 +-- Added error for case executing prepared query after DROP/CREATE EXTENSION. +-- +-- DROP/CREATE extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + create_range_partitions +------------------------- + 10 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +EXECUTE q(1); +ERROR: table "part_test" is not partitioned +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 11 other objects +-- DROP/CREATE disabled extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + create_range_partitions +------------------------- + 10 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +SET pg_pathman.enable = f; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been disabled +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +SET pg_pathman.enable = t; +NOTICE: RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes and some other options have been enabled +EXECUTE q(1); +ERROR: table "part_test" is not partitioned +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 11 other objects +-- DROP/CREATE extension in autonomous transaction +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 198]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 2); + create_range_partitions +------------------------- + 2 +(1 row) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +EXECUTE q(1); + a | b +---+--- +(0 rows) + +BEGIN; + BEGIN AUTONOMOUS; +ERROR: syntax error at or near "AUTONOMOUS" at character 7 + DROP EXTENSION pg_pathman; +ERROR: current transaction is aborted, commands ignored until end of transaction block + CREATE EXTENSION pg_pathman; +ERROR: current transaction is aborted, commands ignored until end of transaction block + COMMIT; +COMMIT; +WARNING: there is no transaction in progress +EXECUTE q(1); + a | b +---+--- +(0 rows) + +DEALLOCATE q; +DROP TABLE part_test CASCADE; +NOTICE: drop cascades to 3 other objects +-- finalize +DROP EXTENSION pg_pathman; diff --git a/sql/pathman_cache_pranks.sql b/sql/pathman_cache_pranks.sql index 782ef7f0..e3fe00d9 100644 --- a/sql/pathman_cache_pranks.sql +++ b/sql/pathman_cache_pranks.sql @@ -48,6 +48,75 @@ SELECT create_hash_partitions('part_test', 'val', 2, partition_names := ARRAY[]: DROP TABLE part_test CASCADE; -- +-- +-- PGPRO-7870 +-- Added error for case executing prepared query after DROP/CREATE EXTENSION. +-- +-- DROP/CREATE extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); + +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; + +EXECUTE q(1); + +DEALLOCATE q; +DROP TABLE part_test CASCADE; + +-- DROP/CREATE disabled extension +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 898]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 10); + +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); + +SET pg_pathman.enable = f; +DROP EXTENSION pg_pathman; +CREATE EXTENSION pg_pathman; +SET pg_pathman.enable = t; + +EXECUTE q(1); + +DEALLOCATE q; +DROP TABLE part_test CASCADE; + +-- DROP/CREATE extension in autonomous transaction +CREATE TABLE part_test(a INT4 NOT NULL, b INT4); +PREPARE q(int4) AS SELECT * FROM part_test WHERE a > ALL (array[$1, 198]); +SELECT create_range_partitions('part_test', 'a', 1, 100, 2); + +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); +EXECUTE q(1); + +BEGIN; + BEGIN AUTONOMOUS; + DROP EXTENSION pg_pathman; + CREATE EXTENSION pg_pathman; + COMMIT; +COMMIT; + +EXECUTE q(1); + +DEALLOCATE q; +DROP TABLE part_test CASCADE; -- finalize DROP EXTENSION pg_pathman; diff --git a/src/nodes_common.c b/src/nodes_common.c index a6fecb51..f4ebc6b1 100644 --- a/src/nodes_common.c +++ b/src/nodes_common.c @@ -601,7 +601,10 @@ create_append_plan_common(PlannerInfo *root, RelOptInfo *rel, CustomScan *cscan; prel = get_pathman_relation_info(rpath->relid); - Assert(prel); + if (!prel) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("table \"%s\" is not partitioned", + get_rel_name_or_relid(rpath->relid)))); cscan = makeNode(CustomScan); cscan->custom_scan_tlist = NIL; /* initial value (empty list) */ @@ -709,7 +712,15 @@ begin_append_common(CustomScanState *node, EState *estate, int eflags) #endif scan_state->prel = get_pathman_relation_info(scan_state->relid); - Assert(scan_state->prel); + /* + * scan_state->prel can be NULL in case execution of prepared query that + * was prepared before DROP/CREATE EXTENSION pg_pathman or after + * pathman_config table truncation etc. + */ + if (!scan_state->prel) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("table \"%s\" is not partitioned", + get_rel_name_or_relid(scan_state->relid)))); /* Prepare expression according to set_set_customscan_references() */ scan_state->prel_expr = PrelExpressionForRelid(scan_state->prel, INDEX_VAR);