From e12fa90ddc05f5ffc21f3240d3cb22beaa6969ac Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 15 Jan 2024 16:44:56 +0100 Subject: [PATCH v4 3/3] Add attstattarget to FormExtraData_pg_attribute This allows setting attstattarget when a relation is created. We make use of this by having index_concurrently_create_copy() copy over the attstattarget values when the new index is created, instead of having index_concurrently_swap() fix it up later. Discussion: https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184c76@eisentraut.org --- src/backend/catalog/heap.c | 5 +- src/backend/catalog/index.c | 97 +++++++++--------------------- src/backend/catalog/toasting.c | 2 +- src/backend/commands/indexcmds.c | 2 +- src/include/catalog/index.h | 1 + src/include/catalog/pg_attribute.h | 1 + 6 files changed, 36 insertions(+), 72 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 70e14d09263..182db28a54d 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -753,18 +753,21 @@ InsertPgAttributeTuples(Relation pg_attribute_rel, slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation); if (attrs_extra) { + slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.value; + slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = attrs_extra->attstattarget.isnull; + slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.value; slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull; } else { + slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true; slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true; } /* * The remaining fields are not set for new columns. */ - slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true; slot[slotCount]->tts_isnull[Anum_pg_attribute_attacl - 1] = true; slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true; slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index f899d15876f..91ce3a21b29 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -112,7 +112,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation, const Oid *opclassIds); static void InitializeAttributeOids(Relation indexRelation, int numatts, Oid indexoid); -static void AppendAttributeTuples(Relation indexRelation, const Datum *attopts); +static void AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets); static void UpdateIndexRelation(Oid indexoid, Oid heapoid, Oid parentIndexId, const IndexInfo *indexInfo, @@ -512,7 +512,7 @@ InitializeAttributeOids(Relation indexRelation, * ---------------------------------------------------------------- */ static void -AppendAttributeTuples(Relation indexRelation, const Datum *attopts) +AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets) { Relation pg_attribute; CatalogIndexState indstate; @@ -529,6 +529,11 @@ AppendAttributeTuples(Relation indexRelation, const Datum *attopts) attrs_extra[i].attoptions.value = attopts[i]; else attrs_extra[i].attoptions.isnull = true; + + if (stattargets) + attrs_extra[i].attstattarget = stattargets[i]; + else + attrs_extra[i].attstattarget.isnull = true; } } @@ -735,6 +740,7 @@ index_create(Relation heapRelation, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, + const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, @@ -1029,7 +1035,7 @@ index_create(Relation heapRelation, /* * append ATTRIBUTE tuples for the index */ - AppendAttributeTuples(indexRelation, opclassOptions); + AppendAttributeTuples(indexRelation, opclassOptions, stattargets); /* ---------------- * update pg_index @@ -1308,6 +1314,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, Datum *opclassOptions; oidvector *indclass; int2vector *indcoloptions; + NullableDatum *stattargets; bool isnull; List *indexColNames = NIL; List *indexExprs = NIL; @@ -1412,6 +1419,23 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++) opclassOptions[i] = get_attoptions(oldIndexId, i + 1); + /* Extra statistic targets for each attribute */ + stattargets = palloc0_array(NullableDatum, newInfo->ii_NumIndexAttrs); + for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++) + { + HeapTuple tp; + Datum dat; + + tp = SearchSysCache2(ATTNUM, ObjectIdGetDatum(oldIndexId), Int16GetDatum(i + 1)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for attribute %d of relation %u", + i + 1, oldIndexId); + dat = SysCacheGetAttr(ATTNUM, tp, Anum_pg_attribute_attstattarget, &isnull); + ReleaseSysCache(tp); + stattargets[i].value = dat; + stattargets[i].isnull = isnull; + } + /* * Now create the new index. * @@ -1433,6 +1457,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, indclass->values, opclassOptions, indcoloptions->values, + stattargets, reloptionsDatum, INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT, 0, @@ -1775,72 +1800,6 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName) /* Copy data of pg_statistic from the old index to the new one */ CopyStatistics(oldIndexId, newIndexId); - /* Copy pg_attribute.attstattarget for each index attribute */ - { - HeapTuple attrTuple; - Relation pg_attribute; - SysScanDesc scan; - ScanKeyData key[1]; - - pg_attribute = table_open(AttributeRelationId, RowExclusiveLock); - ScanKeyInit(&key[0], - Anum_pg_attribute_attrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(newIndexId)); - scan = systable_beginscan(pg_attribute, AttributeRelidNumIndexId, - true, NULL, 1, key); - - while (HeapTupleIsValid((attrTuple = systable_getnext(scan)))) - { - Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attrTuple); - HeapTuple tp; - Datum dat; - bool isnull; - Datum repl_val[Natts_pg_attribute]; - bool repl_null[Natts_pg_attribute]; - bool repl_repl[Natts_pg_attribute]; - HeapTuple newTuple; - - /* Ignore dropped columns */ - if (att->attisdropped) - continue; - - /* - * Get attstattarget from the old index and refresh the new value. - */ - tp = SearchSysCache2(ATTNUM, ObjectIdGetDatum(oldIndexId), Int16GetDatum(att->attnum)); - if (!HeapTupleIsValid(tp)) - elog(ERROR, "cache lookup failed for attribute %d of relation %u", - att->attnum, oldIndexId); - dat = SysCacheGetAttr(ATTNUM, tp, Anum_pg_attribute_attstattarget, &isnull); - ReleaseSysCache(tp); - - /* - * No need for a refresh if old index value is null. (All new - * index values are null at this point.) - */ - if (isnull) - continue; - - memset(repl_val, 0, sizeof(repl_val)); - memset(repl_null, false, sizeof(repl_null)); - memset(repl_repl, false, sizeof(repl_repl)); - - repl_repl[Anum_pg_attribute_attstattarget - 1] = true; - repl_val[Anum_pg_attribute_attstattarget - 1] = dat; - - newTuple = heap_modify_tuple(attrTuple, - RelationGetDescr(pg_attribute), - repl_val, repl_null, repl_repl); - CatalogTupleUpdate(pg_attribute, &newTuple->t_self, newTuple); - - heap_freetuple(newTuple); - } - - systable_endscan(scan); - table_close(pg_attribute, RowExclusiveLock); - } - /* Close relations */ table_close(pg_class, RowExclusiveLock); table_close(pg_index, RowExclusiveLock); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 05d945b34b7..bbdf74ebed3 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -326,7 +326,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, list_make2("chunk_id", "chunk_seq"), BTREE_AM_OID, rel->rd_rel->reltablespace, - collationIds, opclassIds, NULL, coloptions, (Datum) 0, + collationIds, opclassIds, NULL, coloptions, NULL, (Datum) 0, INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL); table_close(toast_rel, NoLock); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 340248a3f29..c2416c11d61 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1193,7 +1193,7 @@ DefineIndex(Oid tableId, stmt->oldNumber, indexInfo, indexColNames, accessMethodId, tablespaceId, collationIds, opclassIds, opclassOptions, - coloptions, reloptions, + coloptions, NULL, reloptions, flags, constr_flags, allowSystemTableMods, !check_rights, &createdConstraintId); diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 99dab5940bc..7d434f8e653 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -80,6 +80,7 @@ extern Oid index_create(Relation heapRelation, const Oid *opclassIds, const Datum *opclassOptions, const int16 *coloptions, + const NullableDatum *stattargets, Datum reloptions, bits16 flags, bits16 constr_flags, diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 27b0077e25b..b28725f4dbe 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute; */ typedef struct FormExtraData_pg_attribute { + NullableDatum attstattarget; NullableDatum attoptions; } FormExtraData_pg_attribute; -- 2.43.0