aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-08-18 12:11:47 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2022-08-18 12:11:47 -0400
commit2cf16cd7497d1dd465f0b1ff67e6c15347233d71 (patch)
treeed63cf5877cd7909e3211ed1f6af586bbe3ad3f3 /src/backend/commands
parentd0e5dc7d30aa1f62ce131b58c4c116b585521f8d (diff)
downloadpostgresql-2cf16cd7497d1dd465f0b1ff67e6c15347233d71.tar.gz
postgresql-2cf16cd7497d1dd465f0b1ff67e6c15347233d71.zip
Fix subtly-incorrect matching of parent and child partitioned indexes.
When creating a partitioned index, DefineIndex tries to identify any existing indexes on the partitions that match the partitioned index, so that it can absorb those as child indexes instead of building new ones. Part of the matching is to compare IndexInfo structs --- but that wasn't done quite right. We're comparing the IndexInfo built within DefineIndex itself to one made from existing catalog contents by BuildIndexInfo. Notably, while BuildIndexInfo will run index expressions and predicates through expression preprocessing, that has not happened to DefineIndex's struct. The result is failure to match and subsequent creation of duplicate indexes. The easiest and most bulletproof fix is to build a new IndexInfo using BuildIndexInfo, thereby guaranteeing that the processing done is identical. While here, let's also extract the opfamily and collation data from the new partitioned index, removing ad-hoc logic that duplicated knowledge about how those are constructed. Per report from Christophe Pettus. Back-patch to v11 where we invented partitioned indexes. Richard Guo and Tom Lane Discussion: https://postgr.es/m/8864BFAA-81FD-4BF9-8E06-7DEB8D4164ED@thebuild.com
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/indexcmds.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index f64df8a55cb..80e05fe3c59 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1141,18 +1141,27 @@ DefineIndex(Oid relationId,
int nparts = partdesc->nparts;
Oid *part_oids = palloc(sizeof(Oid) * nparts);
bool invalidate_parent = false;
+ Relation parentIndex;
TupleDesc parentDesc;
- Oid *opfamOids;
pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_TOTAL,
nparts);
+ /* Make a local copy of partdesc->oids[], just for safety */
memcpy(part_oids, partdesc->oids, sizeof(Oid) * nparts);
+ /*
+ * We'll need an IndexInfo describing the parent index. The one
+ * built above is almost good enough, but not quite, because (for
+ * example) its predicate expression if any hasn't been through
+ * expression preprocessing. The most reliable way to get an
+ * IndexInfo that will match those for child indexes is to build
+ * it the same way, using BuildIndexInfo().
+ */
+ parentIndex = index_open(indexRelationId, lockmode);
+ indexInfo = BuildIndexInfo(parentIndex);
+
parentDesc = RelationGetDescr(rel);
- opfamOids = palloc(sizeof(Oid) * numberOfKeyAttributes);
- for (i = 0; i < numberOfKeyAttributes; i++)
- opfamOids[i] = get_opclass_family(classObjectId[i]);
/*
* For each partition, scan all existing indexes; if one matches
@@ -1226,9 +1235,9 @@ DefineIndex(Oid relationId,
cldIdxInfo = BuildIndexInfo(cldidx);
if (CompareIndexInfo(cldIdxInfo, indexInfo,
cldidx->rd_indcollation,
- collationObjectId,
+ parentIndex->rd_indcollation,
cldidx->rd_opfamily,
- opfamOids,
+ parentIndex->rd_opfamily,
attmap, maplen))
{
Oid cldConstrOid = InvalidOid;
@@ -1353,6 +1362,8 @@ DefineIndex(Oid relationId,
pfree(attmap);
}
+ index_close(parentIndex, lockmode);
+
/*
* The pg_index row we inserted for this index was marked
* indisvalid=true. But if we attached an existing index that is