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.

Reviewed-by: Tomas Vondra <tomas.vondra@enterprisedb.com>
Discussion: https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184c76@eisentraut.org
This commit is contained in:
Peter Eisentraut 2024-03-17 12:38:27 +01:00
parent d939cb2fd6
commit 6a004f1be8
6 changed files with 36 additions and 72 deletions

View File

@ -758,18 +758,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;

View File

@ -107,7 +107,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,
@ -507,7 +507,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;
@ -524,6 +524,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;
}
}
@ -730,6 +735,7 @@ index_create(Relation heapRelation,
const Oid *opclassIds,
const Datum *opclassOptions,
const int16 *coloptions,
const NullableDatum *stattargets,
Datum reloptions,
bits16 flags,
bits16 constr_flags,
@ -1024,7 +1030,7 @@ index_create(Relation heapRelation,
/*
* append ATTRIBUTE tuples for the index
*/
AppendAttributeTuples(indexRelation, opclassOptions);
AppendAttributeTuples(indexRelation, opclassOptions, stattargets);
/* ----------------
* update pg_index
@ -1303,6 +1309,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;
@ -1407,6 +1414,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);
/* Extract 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.
*
@ -1428,6 +1452,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
indclass->values,
opclassOptions,
indcoloptions->values,
stattargets,
reloptionsDatum,
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
0,
@ -1771,72 +1796,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);

View File

@ -323,7 +323,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);

View File

@ -1210,7 +1210,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);

View File

@ -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,

View File

@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
*/
typedef struct FormExtraData_pg_attribute
{
NullableDatum attstattarget;
NullableDatum attoptions;
} FormExtraData_pg_attribute;