diff --git a/contrib/seg/Makefile b/contrib/seg/Makefile index 132ec8dbfea..b408f4049cb 100644 --- a/contrib/seg/Makefile +++ b/contrib/seg/Makefile @@ -14,7 +14,7 @@ PGFILEDESC = "seg - line segment data type" HEADERS = segdata.h -REGRESS = security seg +REGRESS = security seg partition EXTRA_CLEAN = segparse.h segparse.c segscan.c diff --git a/contrib/seg/expected/partition.out b/contrib/seg/expected/partition.out new file mode 100644 index 00000000000..90d8397d5d4 --- /dev/null +++ b/contrib/seg/expected/partition.out @@ -0,0 +1,54 @@ +-- +-- Test that partitioned-index operations cope with objects that are +-- not in the secure search path. (This has little to do with seg, +-- but we need an opclass that isn't in pg_catalog, and the base system +-- has no such opclass.) Note that we need to test propagation of the +-- partitioned index's properties both to partitions that pre-date it +-- and to partitions created later. +-- +create function mydouble(int) returns int strict immutable parallel safe +begin atomic select $1 * 2; end; +create collation mycollation from "POSIX"; +create table pt (category int, sdata seg, tdata text) + partition by list (category); +-- pre-existing partition +create table pt12 partition of pt for values in (1,2); +insert into pt values(1, '0 .. 1'::seg, 'zed'); +-- expression references object in public schema +create index pti1 on pt ((mydouble(category) + 1)); +-- opclass in public schema +create index pti2 on pt (sdata seg_ops); +-- collation in public schema +create index pti3 on pt (tdata collate mycollation); +-- new partition +create table pt34 partition of pt for values in (3,4); +insert into pt values(4, '-1 .. 1'::seg, 'foo'); +\d+ pt + Partitioned table "public.pt" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+----------+--------------+------------- + category | integer | | | | plain | | + sdata | seg | | | | plain | | + tdata | text | | | | extended | | +Partition key: LIST (category) +Indexes: + "pti1" btree ((mydouble(category) + 1)) + "pti2" btree (sdata) + "pti3" btree (tdata COLLATE mycollation) +Partitions: pt12 FOR VALUES IN (1, 2), + pt34 FOR VALUES IN (3, 4) + +\d+ pt12 + Table "public.pt12" + Column | Type | Collation | Nullable | Default | Storage | Stats target | Description +----------+---------+-----------+----------+---------+----------+--------------+------------- + category | integer | | | | plain | | + sdata | seg | | | | plain | | + tdata | text | | | | extended | | +Partition of: pt FOR VALUES IN (1, 2) +Partition constraint: ((category IS NOT NULL) AND (category = ANY (ARRAY[1, 2]))) +Indexes: + "pt12_expr_idx" btree ((mydouble(category) + 1)) + "pt12_sdata_idx" btree (sdata) + "pt12_tdata_idx" btree (tdata COLLATE mycollation) + diff --git a/contrib/seg/meson.build b/contrib/seg/meson.build index abeaf08eff1..018ba5591ae 100644 --- a/contrib/seg/meson.build +++ b/contrib/seg/meson.build @@ -55,6 +55,7 @@ tests += { 'sql': [ 'security', 'seg', + 'partition', ], }, } diff --git a/contrib/seg/sql/partition.sql b/contrib/seg/sql/partition.sql new file mode 100644 index 00000000000..e1febdea873 --- /dev/null +++ b/contrib/seg/sql/partition.sql @@ -0,0 +1,36 @@ +-- +-- Test that partitioned-index operations cope with objects that are +-- not in the secure search path. (This has little to do with seg, +-- but we need an opclass that isn't in pg_catalog, and the base system +-- has no such opclass.) Note that we need to test propagation of the +-- partitioned index's properties both to partitions that pre-date it +-- and to partitions created later. +-- + +create function mydouble(int) returns int strict immutable parallel safe +begin atomic select $1 * 2; end; + +create collation mycollation from "POSIX"; + +create table pt (category int, sdata seg, tdata text) + partition by list (category); + +-- pre-existing partition +create table pt12 partition of pt for values in (1,2); + +insert into pt values(1, '0 .. 1'::seg, 'zed'); + +-- expression references object in public schema +create index pti1 on pt ((mydouble(category) + 1)); +-- opclass in public schema +create index pti2 on pt (sdata seg_ops); +-- collation in public schema +create index pti3 on pt (tdata collate mycollation); + +-- new partition +create table pt34 partition of pt for values in (3,4); + +insert into pt values(4, '-1 .. 1'::seg, 'foo'); + +\d+ pt +\d+ pt12 diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 130cebd6588..e33ad815295 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -51,6 +51,7 @@ #include "optimizer/optimizer.h" #include "parser/parse_coerce.h" #include "parser/parse_oper.h" +#include "parser/parse_utilcmd.h" #include "partitioning/partdesc.h" #include "pgstat.h" #include "rewrite/rewriteManip.h" @@ -1465,55 +1466,20 @@ DefineIndex(Oid tableId, */ if (!found) { - IndexStmt *childStmt = copyObject(stmt); - bool found_whole_row; - ListCell *lc; + IndexStmt *childStmt; ObjectAddress childAddr; /* - * We can't use the same index name for the child index, - * so clear idxname to let the recursive invocation choose - * a new name. Likewise, the existing target relation - * field is wrong, and if indexOid or oldNumber are set, - * they mustn't be applied to the child either. + * Build an IndexStmt describing the desired child index + * in the same way that we do during ATTACH PARTITION. + * Notably, we rely on generateClonedIndexStmt to produce + * a search-path-independent representation, which the + * original IndexStmt might not be. */ - childStmt->idxname = NULL; - childStmt->relation = NULL; - childStmt->indexOid = InvalidOid; - childStmt->oldNumber = InvalidRelFileNumber; - childStmt->oldCreateSubid = InvalidSubTransactionId; - childStmt->oldFirstRelfilelocatorSubid = InvalidSubTransactionId; - - /* - * Adjust any Vars (both in expressions and in the index's - * WHERE clause) to match the partition's column numbering - * in case it's different from the parent's. - */ - foreach(lc, childStmt->indexParams) - { - IndexElem *ielem = lfirst(lc); - - /* - * If the index parameter is an expression, we must - * translate it to contain child Vars. - */ - if (ielem->expr) - { - ielem->expr = - map_variable_attnos((Node *) ielem->expr, - 1, 0, attmap, - InvalidOid, - &found_whole_row); - if (found_whole_row) - elog(ERROR, "cannot convert whole-row table reference"); - } - } - childStmt->whereClause = - map_variable_attnos(stmt->whereClause, 1, 0, - attmap, - InvalidOid, &found_whole_row); - if (found_whole_row) - elog(ERROR, "cannot convert whole-row table reference"); + childStmt = generateClonedIndexStmt(NULL, + parentIndex, + attmap, + NULL); /* * Recurse as the starting user ID. Callee will use that diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index fb8db37623d..143ae7c09c0 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -2215,7 +2215,6 @@ select conname, obj_description(oid, 'pg_constraint') as desc (3 rows) alter table at_partitioned alter column name type varchar(127); --- Note: these tests currently show the wrong behavior for comments :-( select relname, c.oid = oldoid as orig_oid, case relfilenode @@ -2232,9 +2231,9 @@ select relname, ------------------------------+----------+---------+-------------- at_partitioned | t | none | at_partitioned_0 | t | own | - at_partitioned_0_id_name_key | f | own | parent index + at_partitioned_0_id_name_key | f | own | at_partitioned_1 | t | own | - at_partitioned_1_id_name_key | f | own | parent index + at_partitioned_1_id_name_key | f | own | at_partitioned_id_name_key | f | none | parent index (6 rows) diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index cba15ebfec8..c5dd43a15c4 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -1496,8 +1496,6 @@ select conname, obj_description(oid, 'pg_constraint') as desc alter table at_partitioned alter column name type varchar(127); --- Note: these tests currently show the wrong behavior for comments :-( - select relname, c.oid = oldoid as orig_oid, case relfilenode