Add attstattarget to FormExtraData_pg_attribute
authorPeter Eisentraut <[email protected]>
Sun, 17 Mar 2024 11:38:27 +0000 (12:38 +0100)
committerPeter Eisentraut <[email protected]>
Sun, 17 Mar 2024 11:38:27 +0000 (12:38 +0100)
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 <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184c76@eisentraut.org

src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/toasting.c
src/backend/commands/indexcmds.c
src/include/catalog/index.h
src/include/catalog/pg_attribute.h

index de982c2c529e59852c82162688589819d90a206b..cc31909012d513dbc129b4d630970e2e26acc0ed 100644 (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;
index 7e428f3eb79dc8800df13ea6213168dbd6530906..b6a7c60e230fc9afe18aa669a1e1351b4a1e0449 100644 (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);
index 21be81c1fb37ea3196b1eb22d2a337614a604de5..738bc46ae8293cf45d8ffdbda90b1dd41d1213ea 100644 (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);
index de89be8d759721aee500b3f076ea60ac2e4f9ca6..7b20d103c867165bcf1c53abb2f541b100d9d235 100644 (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);
index 2ef8512dbffe8fc28e04995f7b5af5750d85718f..2dea96f47c396648bfa992b07414b5a0ac1c5b31 100644 (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,
index 1cc7a848f03df6f344e94bc87a84c5f2e66cdb71..1c62b8bfcb58e244e45d45bd57f923e6a0d23bba 100644 (file)
@@ -218,6 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
  */
 typedef struct FormExtraData_pg_attribute
 {
+   NullableDatum attstattarget;
    NullableDatum attoptions;
 } FormExtraData_pg_attribute;