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);
|
slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation);
|
||||||
if (attrs_extra)
|
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_values[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.value;
|
||||||
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull;
|
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = attrs_extra->attoptions.isnull;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
slot[slotCount]->tts_isnull[Anum_pg_attribute_attstattarget - 1] = true;
|
||||||
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
|
slot[slotCount]->tts_isnull[Anum_pg_attribute_attoptions - 1] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The remaining fields are not set for new columns.
|
* 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_attacl - 1] = true;
|
||||||
slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true;
|
slot[slotCount]->tts_isnull[Anum_pg_attribute_attfdwoptions - 1] = true;
|
||||||
slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true;
|
slot[slotCount]->tts_isnull[Anum_pg_attribute_attmissingval - 1] = true;
|
||||||
|
|
|
@ -107,7 +107,7 @@ static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
||||||
const Oid *opclassIds);
|
const Oid *opclassIds);
|
||||||
static void InitializeAttributeOids(Relation indexRelation,
|
static void InitializeAttributeOids(Relation indexRelation,
|
||||||
int numatts, Oid indexoid);
|
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,
|
static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
|
||||||
Oid parentIndexId,
|
Oid parentIndexId,
|
||||||
const IndexInfo *indexInfo,
|
const IndexInfo *indexInfo,
|
||||||
|
@ -507,7 +507,7 @@ InitializeAttributeOids(Relation indexRelation,
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
AppendAttributeTuples(Relation indexRelation, const Datum *attopts)
|
AppendAttributeTuples(Relation indexRelation, const Datum *attopts, const NullableDatum *stattargets)
|
||||||
{
|
{
|
||||||
Relation pg_attribute;
|
Relation pg_attribute;
|
||||||
CatalogIndexState indstate;
|
CatalogIndexState indstate;
|
||||||
|
@ -524,6 +524,11 @@ AppendAttributeTuples(Relation indexRelation, const Datum *attopts)
|
||||||
attrs_extra[i].attoptions.value = attopts[i];
|
attrs_extra[i].attoptions.value = attopts[i];
|
||||||
else
|
else
|
||||||
attrs_extra[i].attoptions.isnull = true;
|
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 Oid *opclassIds,
|
||||||
const Datum *opclassOptions,
|
const Datum *opclassOptions,
|
||||||
const int16 *coloptions,
|
const int16 *coloptions,
|
||||||
|
const NullableDatum *stattargets,
|
||||||
Datum reloptions,
|
Datum reloptions,
|
||||||
bits16 flags,
|
bits16 flags,
|
||||||
bits16 constr_flags,
|
bits16 constr_flags,
|
||||||
|
@ -1024,7 +1030,7 @@ index_create(Relation heapRelation,
|
||||||
/*
|
/*
|
||||||
* append ATTRIBUTE tuples for the index
|
* append ATTRIBUTE tuples for the index
|
||||||
*/
|
*/
|
||||||
AppendAttributeTuples(indexRelation, opclassOptions);
|
AppendAttributeTuples(indexRelation, opclassOptions, stattargets);
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* update pg_index
|
* update pg_index
|
||||||
|
@ -1303,6 +1309,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
|
||||||
Datum *opclassOptions;
|
Datum *opclassOptions;
|
||||||
oidvector *indclass;
|
oidvector *indclass;
|
||||||
int2vector *indcoloptions;
|
int2vector *indcoloptions;
|
||||||
|
NullableDatum *stattargets;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
List *indexColNames = NIL;
|
List *indexColNames = NIL;
|
||||||
List *indexExprs = 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++)
|
for (int i = 0; i < newInfo->ii_NumIndexAttrs; i++)
|
||||||
opclassOptions[i] = get_attoptions(oldIndexId, i + 1);
|
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.
|
* Now create the new index.
|
||||||
*
|
*
|
||||||
|
@ -1428,6 +1452,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
|
||||||
indclass->values,
|
indclass->values,
|
||||||
opclassOptions,
|
opclassOptions,
|
||||||
indcoloptions->values,
|
indcoloptions->values,
|
||||||
|
stattargets,
|
||||||
reloptionsDatum,
|
reloptionsDatum,
|
||||||
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
|
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
|
||||||
0,
|
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 */
|
/* Copy data of pg_statistic from the old index to the new one */
|
||||||
CopyStatistics(oldIndexId, newIndexId);
|
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 */
|
/* Close relations */
|
||||||
table_close(pg_class, RowExclusiveLock);
|
table_close(pg_class, RowExclusiveLock);
|
||||||
table_close(pg_index, 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"),
|
list_make2("chunk_id", "chunk_seq"),
|
||||||
BTREE_AM_OID,
|
BTREE_AM_OID,
|
||||||
rel->rd_rel->reltablespace,
|
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);
|
INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
|
||||||
|
|
||||||
table_close(toast_rel, NoLock);
|
table_close(toast_rel, NoLock);
|
||||||
|
|
|
@ -1210,7 +1210,7 @@ DefineIndex(Oid tableId,
|
||||||
stmt->oldNumber, indexInfo, indexColNames,
|
stmt->oldNumber, indexInfo, indexColNames,
|
||||||
accessMethodId, tablespaceId,
|
accessMethodId, tablespaceId,
|
||||||
collationIds, opclassIds, opclassOptions,
|
collationIds, opclassIds, opclassOptions,
|
||||||
coloptions, reloptions,
|
coloptions, NULL, reloptions,
|
||||||
flags, constr_flags,
|
flags, constr_flags,
|
||||||
allowSystemTableMods, !check_rights,
|
allowSystemTableMods, !check_rights,
|
||||||
&createdConstraintId);
|
&createdConstraintId);
|
||||||
|
|
|
@ -80,6 +80,7 @@ extern Oid index_create(Relation heapRelation,
|
||||||
const Oid *opclassIds,
|
const Oid *opclassIds,
|
||||||
const Datum *opclassOptions,
|
const Datum *opclassOptions,
|
||||||
const int16 *coloptions,
|
const int16 *coloptions,
|
||||||
|
const NullableDatum *stattargets,
|
||||||
Datum reloptions,
|
Datum reloptions,
|
||||||
bits16 flags,
|
bits16 flags,
|
||||||
bits16 constr_flags,
|
bits16 constr_flags,
|
||||||
|
|
|
@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
|
||||||
*/
|
*/
|
||||||
typedef struct FormExtraData_pg_attribute
|
typedef struct FormExtraData_pg_attribute
|
||||||
{
|
{
|
||||||
|
NullableDatum attstattarget;
|
||||||
NullableDatum attoptions;
|
NullableDatum attoptions;
|
||||||
} FormExtraData_pg_attribute;
|
} FormExtraData_pg_attribute;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue