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:
parent
d939cb2fd6
commit
6a004f1be8
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
|
||||
*/
|
||||
typedef struct FormExtraData_pg_attribute
|
||||
{
|
||||
NullableDatum attstattarget;
|
||||
NullableDatum attoptions;
|
||||
} FormExtraData_pg_attribute;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user