Save a few bytes in pg_attribute
authorPeter Eisentraut <peter@eisentraut.org>
Tue, 28 Mar 2023 07:58:14 +0000 (09:58 +0200)
committerPeter Eisentraut <peter@eisentraut.org>
Tue, 28 Mar 2023 08:05:56 +0000 (10:05 +0200)
Change the columns attndims, attstattarget, and attinhcount from int32
to int16, and reorder a bit.  This saves some space (currently 4
bytes) in pg_attribute and tuple descriptors, which translates into
small performance benefits and/or room for new columns in pg_attribute
needed by future features.

attndims and attinhcount are never realistically used with values
larger than int16.  Just to be sure, add some overflow checks.
attstattarget is currently limited explicitly to 10000.

For consistency, pg_constraint.coninhcount is also changed like
attinhcount.

Discussion: https://www.postgresql.org/message-id/flat/d07ffc2b-e0e8-77f7-38fb-be921dff71af%40enterprisedb.com

doc/src/sgml/catalogs.sgml
src/backend/access/common/tupdesc.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/pg_constraint.c
src/backend/commands/tablecmds.c
src/include/catalog/catversion.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_constraint.h

index 746baf505385b45e90ae5c7802c7f0d84cb0222f..7c09ab300064759406798db7315f9fd42d1bf307 100644 (file)
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>attstattarget</structfield> <type>int4</type>
-      </para>
-      <para>
-       <structfield>attstattarget</structfield> controls the level of detail
-       of statistics accumulated for this column by
-       <link linkend="sql-analyze"><command>ANALYZE</command></link>.
-       A zero value indicates that no statistics should be collected.
-       A negative value says to use the system default statistics target.
-       The exact meaning of positive values is data type-dependent.
-       For scalar data types, <structfield>attstattarget</structfield>
-       is both the target number of <quote>most common values</quote>
-       to collect, and the target number of histogram bins to create.
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>attlen</structfield> <type>int2</type>
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>attndims</structfield> <type>int4</type>
-      </para>
-      <para>
-       Number of dimensions, if the column is an array type; otherwise 0.
-       (Presently, the number of dimensions of an array is not enforced,
-       so any nonzero value effectively means <quote>it's an array</quote>.)
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>attcacheoff</structfield> <type>int4</type>
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>attndims</structfield> <type>int2</type>
+      </para>
+      <para>
+       Number of dimensions, if the column is an array type; otherwise 0.
+       (Presently, the number of dimensions of an array is not enforced,
+       so any nonzero value effectively means <quote>it's an array</quote>.)
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>attbyval</structfield> <type>bool</type>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>attinhcount</structfield> <type>int4</type>
+       <structfield>attinhcount</structfield> <type>int2</type>
       </para>
       <para>
        The number of direct ancestors this column has.  A column with a
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>attstattarget</structfield> <type>int2</type>
+      </para>
+      <para>
+       <structfield>attstattarget</structfield> controls the level of detail
+       of statistics accumulated for this column by
+       <link linkend="sql-analyze"><command>ANALYZE</command></link>.
+       A zero value indicates that no statistics should be collected.
+       A negative value says to use the system default statistics target.
+       The exact meaning of positive values is data type-dependent.
+       For scalar data types, <structfield>attstattarget</structfield>
+       is both the target number of <quote>most common values</quote>
+       to collect, and the target number of histogram bins to create.
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>attcollation</structfield> <type>oid</type>
@@ -2691,7 +2691,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>coninhcount</structfield> <type>int4</type>
+       <structfield>coninhcount</structfield> <type>int2</type>
       </para>
       <para>
        The number of direct inheritance ancestors this constraint has.
index 72a2c3d3db61752555a2573f74759d9797f6ae97..7c5c390503b44276e648a47ecf2c82ce7f445a65 100644 (file)
@@ -597,6 +597,8 @@ TupleDescInitEntry(TupleDesc desc,
    Assert(PointerIsValid(desc));
    Assert(attributeNumber >= 1);
    Assert(attributeNumber <= desc->natts);
+   Assert(attdim >= 0);
+   Assert(attdim <= PG_INT16_MAX);
 
    /*
     * initialize the attribute fields
@@ -667,6 +669,8 @@ TupleDescInitBuiltinEntry(TupleDesc desc,
    Assert(PointerIsValid(desc));
    Assert(attributeNumber >= 1);
    Assert(attributeNumber <= desc->natts);
+   Assert(attdim >= 0);
+   Assert(attdim <= PG_INT16_MAX);
 
    /* initialize the attribute fields */
    att = TupleDescAttr(desc, attributeNumber - 1);
@@ -827,6 +831,10 @@ BuildDescForRelation(List *schema)
 
        attcollation = GetColumnDefCollation(NULL, entry, atttypid);
        attdim = list_length(entry->typeName->arrayBounds);
+       if (attdim > PG_INT16_MAX)
+           ereport(ERROR,
+                   errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                   errmsg("too many array dimensions"));
 
        if (entry->typeName->setof)
            ereport(ERROR,
index 4f006820b85dbb4d19c42b51f448348bbf35a58c..2a0d82aedd7c718f9a7b5ed4bc35a4952d800e5c 100644 (file)
@@ -732,12 +732,11 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
 
        slot[slotCount]->tts_values[Anum_pg_attribute_attname - 1] = NameGetDatum(&attrs->attname);
        slot[slotCount]->tts_values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(attrs->atttypid);
-       slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attrs->attstattarget);
        slot[slotCount]->tts_values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(attrs->attlen);
        slot[slotCount]->tts_values[Anum_pg_attribute_attnum - 1] = Int16GetDatum(attrs->attnum);
-       slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int32GetDatum(attrs->attndims);
        slot[slotCount]->tts_values[Anum_pg_attribute_attcacheoff - 1] = Int32GetDatum(-1);
        slot[slotCount]->tts_values[Anum_pg_attribute_atttypmod - 1] = Int32GetDatum(attrs->atttypmod);
+       slot[slotCount]->tts_values[Anum_pg_attribute_attndims - 1] = Int16GetDatum(attrs->attndims);
        slot[slotCount]->tts_values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(attrs->attbyval);
        slot[slotCount]->tts_values[Anum_pg_attribute_attalign - 1] = CharGetDatum(attrs->attalign);
        slot[slotCount]->tts_values[Anum_pg_attribute_attstorage - 1] = CharGetDatum(attrs->attstorage);
@@ -749,7 +748,8 @@ InsertPgAttributeTuples(Relation pg_attribute_rel,
        slot[slotCount]->tts_values[Anum_pg_attribute_attgenerated - 1] = CharGetDatum(attrs->attgenerated);
        slot[slotCount]->tts_values[Anum_pg_attribute_attisdropped - 1] = BoolGetDatum(attrs->attisdropped);
        slot[slotCount]->tts_values[Anum_pg_attribute_attislocal - 1] = BoolGetDatum(attrs->attislocal);
-       slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int32GetDatum(attrs->attinhcount);
+       slot[slotCount]->tts_values[Anum_pg_attribute_attinhcount - 1] = Int16GetDatum(attrs->attinhcount);
+       slot[slotCount]->tts_values[Anum_pg_attribute_attstattarget - 1] = Int16GetDatum(attrs->attstattarget);
        slot[slotCount]->tts_values[Anum_pg_attribute_attcollation - 1] = ObjectIdGetDatum(attrs->attcollation);
        if (attoptions && attoptions[natts] != (Datum) 0)
            slot[slotCount]->tts_values[Anum_pg_attribute_attoptions - 1] = attoptions[natts];
@@ -2615,6 +2615,11 @@ MergeWithExistingConstraint(Relation rel, const char *ccname, Node *expr,
                con->conislocal = true;
            else
                con->coninhcount++;
+
+           if (con->coninhcount < 0)
+               ereport(ERROR,
+                       errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                       errmsg("too many inheritance parents"));
        }
 
        if (is_no_inherit)
index c64fde4b7949babe74c057ac50ecd5cd3da3cb61..6aec1b1bca2135395896b78e5d8f7d462fce0064 100644 (file)
@@ -1809,7 +1809,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
            memset(repl_repl, false, sizeof(repl_repl));
 
            repl_repl[Anum_pg_attribute_attstattarget - 1] = true;
-           repl_val[Anum_pg_attribute_attstattarget - 1] = Int32GetDatum(attstattarget);
+           repl_val[Anum_pg_attribute_attstattarget - 1] = Int16GetDatum(attstattarget);
 
            newTuple = heap_modify_tuple(attrTuple,
                                         RelationGetDescr(pg_attribute),
index ce82ede7f9010fe5b18f2478067e41a5c41ca516..4002317f7050244833c1110f12bba6b6435bee65 100644 (file)
@@ -190,7 +190,7 @@ CreateConstraintEntry(const char *constraintName,
    values[Anum_pg_constraint_confdeltype - 1] = CharGetDatum(foreignDeleteType);
    values[Anum_pg_constraint_confmatchtype - 1] = CharGetDatum(foreignMatchType);
    values[Anum_pg_constraint_conislocal - 1] = BoolGetDatum(conIsLocal);
-   values[Anum_pg_constraint_coninhcount - 1] = Int32GetDatum(conInhCount);
+   values[Anum_pg_constraint_coninhcount - 1] = Int16GetDatum(conInhCount);
    values[Anum_pg_constraint_connoinherit - 1] = BoolGetDatum(conNoInherit);
 
    if (conkeyArray)
@@ -805,6 +805,10 @@ ConstraintSetParentConstraint(Oid childConstrId,
 
        constrForm->conislocal = false;
        constrForm->coninhcount++;
+       if (constrForm->coninhcount < 0)
+           ereport(ERROR,
+                   errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                   errmsg("too many inheritance parents"));
        constrForm->conparentid = parentConstrId;
 
        CatalogTupleUpdate(constrRel, &tuple->t_self, newtup);
index c510a01fd8dd9445dc1c6b7134c8c75252db2216..3147dddf286849db5b95db72020ca095c125c33d 100644 (file)
@@ -2650,6 +2650,10 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
                 */
 
                def->inhcount++;
+               if (def->inhcount < 0)
+                   ereport(ERROR,
+                           errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                           errmsg("too many inheritance parents"));
 
                newattmap->attnums[parent_attno - 1] = exist_attno;
            }
@@ -3173,6 +3177,10 @@ MergeCheckConstraint(List *constraints, char *name, Node *expr)
        {
            /* OK to merge */
            ccon->inhcount++;
+           if (ccon->inhcount < 0)
+               ereport(ERROR,
+                       errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                       errmsg("too many inheritance parents"));
            return true;
        }
 
@@ -6828,6 +6836,10 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 
            /* Bump the existing child att's inhcount */
            childatt->attinhcount++;
+           if (childatt->attinhcount < 0)
+               ereport(ERROR,
+                       errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                       errmsg("too many inheritance parents"));
            CatalogTupleUpdate(attrdesc, &tuple->t_self, tuple);
 
            heap_freetuple(tuple);
@@ -6919,6 +6931,10 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
    attribute.attstattarget = (newattnum > 0) ? -1 : 0;
    attribute.attlen = tform->typlen;
    attribute.attnum = newattnum;
+   if (list_length(colDef->typeName->arrayBounds) > PG_INT16_MAX)
+       ereport(ERROR,
+               errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+               errmsg("too many array dimensions"));
    attribute.attndims = list_length(colDef->typeName->arrayBounds);
    attribute.atttypmod = typmod;
    attribute.attbyval = tform->typbyval;
@@ -12924,6 +12940,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
    attTup->atttypid = targettype;
    attTup->atttypmod = targettypmod;
    attTup->attcollation = targetcollid;
+   if (list_length(typeName->arrayBounds) > PG_INT16_MAX)
+       ereport(ERROR,
+               errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+               errmsg("too many array dimensions"));
    attTup->attndims = list_length(typeName->arrayBounds);
    attTup->attlen = tform->typlen;
    attTup->attbyval = tform->typbyval;
@@ -15155,6 +15175,10 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
             * later on, this change will just roll back.)
             */
            childatt->attinhcount++;
+           if (childatt->attinhcount < 0)
+               ereport(ERROR,
+                       errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                       errmsg("too many inheritance parents"));
 
            /*
             * In case of partitions, we must enforce that value of attislocal
@@ -15292,6 +15316,10 @@ MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
            child_copy = heap_copytuple(child_tuple);
            child_con = (Form_pg_constraint) GETSTRUCT(child_copy);
            child_con->coninhcount++;
+           if (child_con->coninhcount < 0)
+               ereport(ERROR,
+                       errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                       errmsg("too many inheritance parents"));
 
            /*
             * In case of partitions, an inherited constraint must be
index 69270c313f6084f0afbe0d7de7f72b4ff51e3981..c187d47eb27c6b6584d71ccfa646abd495e0f522 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202303231
+#define CATALOG_VERSION_NO 202303281
 
 #endif
index b561e1778104edc8a6d694a630175938b3e60cd4..f8b4861b94ab569d368bcf31dd6a08e14674791a 100644 (file)
@@ -52,15 +52,6 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
     */
    Oid         atttypid BKI_LOOKUP_OPT(pg_type);
 
-   /*
-    * attstattarget is the target number of statistics datapoints to collect
-    * during VACUUM ANALYZE of this column.  A zero here indicates that we do
-    * not wish to collect any stats about this column. A "-1" here indicates
-    * that no value has been explicitly set for this column, so ANALYZE
-    * should use the default setting.
-    */
-   int32       attstattarget BKI_DEFAULT(-1);
-
    /*
     * attlen is a copy of the typlen field from pg_type for this attribute.
     * See atttypid comments above.
@@ -82,12 +73,6 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
     */
    int16       attnum;
 
-   /*
-    * attndims is the declared number of dimensions, if an array type,
-    * otherwise zero.
-    */
-   int32       attndims;
-
    /*
     * fastgetattr() uses attcacheoff to cache byte offsets of attributes in
     * heap tuples.  The value actually stored in pg_attribute (-1) indicates
@@ -105,6 +90,12 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
     */
    int32       atttypmod BKI_DEFAULT(-1);
 
+   /*
+    * attndims is the declared number of dimensions, if an array type,
+    * otherwise zero.
+    */
+   int16       attndims;
+
    /*
     * attbyval is a copy of the typbyval field from pg_type for this
     * attribute.  See atttypid comments above.
@@ -165,7 +156,18 @@ CATALOG(pg_attribute,1249,AttributeRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(75,
    bool        attislocal BKI_DEFAULT(t);
 
    /* Number of times inherited from direct parent relation(s) */
-   int32       attinhcount BKI_DEFAULT(0);
+   int16       attinhcount BKI_DEFAULT(0);
+
+   /*
+    * attstattarget is the target number of statistics datapoints to collect
+    * during VACUUM ANALYZE of this column.  A zero here indicates that we do
+    * not wish to collect any stats about this column. A "-1" here indicates
+    * that no value has been explicitly set for this column, so ANALYZE
+    * should use the default setting.
+    *
+    * int16 is sufficient because the max value is currently 10000.
+    */
+   int16       attstattarget BKI_DEFAULT(-1);
 
    /* attribute's collation, if any */
    Oid         attcollation BKI_LOOKUP_OPT(pg_collation);
index 96889fddfaf934f07c3271ef1652816ff655729c..16bf5f5576e2625711898d28673d4d0450e37d8d 100644 (file)
@@ -102,7 +102,7 @@ CATALOG(pg_constraint,2606,ConstraintRelationId)
    bool        conislocal;
 
    /* Number of times inherited from direct parent relation(s) */
-   int32       coninhcount;
+   int16       coninhcount;
 
    /* Has a local definition and cannot be inherited */
    bool        connoinherit;