Make stxstattarget nullable
authorPeter Eisentraut <peter@eisentraut.org>
Sun, 17 Mar 2024 11:22:05 +0000 (12:22 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Sun, 17 Mar 2024 11:26:26 +0000 (12:26 +0100)
To match attstattarget change (commit 4f622503d6d).  The logic inside
CreateStatistics() is clarified a bit compared to that previous patch,
and so here we also update ATExecSetStatistics() to match.

Reviewed-by: Tomas Vondra <tomas.vondra@enterprisedb.com>
Discussion: https://www.postgresql.org/message-id/flat/4da8d211-d54d-44b9-9847-f2a9f1184c76@eisentraut.org

doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/alter_statistics.sgml
src/backend/commands/statscmds.c
src/backend/commands/tablecmds.c
src/backend/parser/gram.y
src/backend/statistics/extended_stats.c
src/bin/pg_dump/pg_dump.c
src/bin/psql/describe.c
src/include/catalog/catversion.h
src/include/catalog/pg_statistic_ext.h
src/include/nodes/parsenodes.h

index 387a14b18691bf3f3096be590b529fd873fceb38..2f091ad09d1d5af918cca53b121e20e0c2ad5c1d 100644 (file)
@@ -7657,6 +7657,19 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>stxkeys</structfield> <type>int2vector</type>
+       (references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
+      </para>
+      <para>
+       An array of attribute numbers, indicating which table columns are
+       covered by this statistics object;
+       for example a value of <literal>1 3</literal> would
+       mean that the first and the third table columns are covered
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>stxstattarget</structfield> <type>int2</type>
@@ -7666,7 +7679,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        of statistics accumulated for this statistics object 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 maximum of the statistics targets of
+       A null value says to use the maximum of the statistics targets of
        the referenced columns, if set, or the system default statistics target.
        Positive values of <structfield>stxstattarget</structfield>
        determine the target number of <quote>most common values</quote>
@@ -7674,19 +7687,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>stxkeys</structfield> <type>int2vector</type>
-       (references <link linkend="catalog-pg-attribute"><structname>pg_attribute</structname></link>.<structfield>attnum</structfield>)
-      </para>
-      <para>
-       An array of attribute numbers, indicating which table columns are
-       covered by this statistics object;
-       for example a value of <literal>1 3</literal> would
-       mean that the first and the third table columns are covered
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>stxkind</structfield> <type>char[]</type>
index 73cc9e830de5bd2f806df8234f4acf3b3deefa94..c82a728a910ee7d1580fafd442ad6d538037cdfb 100644 (file)
@@ -26,7 +26,7 @@ PostgreSQL documentation
 ALTER STATISTICS <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable class="parameter">new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
 ALTER STATISTICS <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
 ALTER STATISTICS <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
-ALTER STATISTICS <replaceable class="parameter">name</replaceable> SET STATISTICS <replaceable class="parameter">new_target</replaceable>
+ALTER STATISTICS <replaceable class="parameter">name</replaceable> SET STATISTICS { <replaceable class="parameter">new_target</replaceable> | DEFAULT }
 </synopsis>
  </refsynopsisdiv>
 
@@ -101,10 +101,11 @@ ALTER STATISTICS <replaceable class="parameter">name</replaceable> SET STATISTIC
        <para>
         The statistic-gathering target for this statistics object for subsequent
         <link linkend="sql-analyze"><command>ANALYZE</command></link> operations.
-        The target can be set in the range 0 to 10000; alternatively, set it
-        to -1 to revert to using the maximum of the statistics target of the
-        referenced columns, if set, or the system default statistics
-        target (<xref linkend="guc-default-statistics-target"/>).
+        The target can be set in the range 0 to 10000.  Set it to
+        <literal>DEFAULT</literal> to revert to using the system default
+        statistics target (<xref linkend="guc-default-statistics-target"/>).
+        (Setting to a value of -1 is an obsolete way spelling to get the same
+        outcome.)
         For more information on the use of statistics by the
         <productname>PostgreSQL</productname> query planner, refer to
         <xref linkend="planner-stats"/>.
index a855f750c751fe90140795883a5a23c118c1d24d..5f49479832d9192a7d28a704c2d465aa8d20f214 100644 (file)
@@ -495,9 +495,9 @@ CreateStatistics(CreateStatsStmt *stmt)
    values[Anum_pg_statistic_ext_stxrelid - 1] = ObjectIdGetDatum(relid);
    values[Anum_pg_statistic_ext_stxname - 1] = NameGetDatum(&stxname);
    values[Anum_pg_statistic_ext_stxnamespace - 1] = ObjectIdGetDatum(namespaceId);
-   values[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(-1);
    values[Anum_pg_statistic_ext_stxowner - 1] = ObjectIdGetDatum(stxowner);
    values[Anum_pg_statistic_ext_stxkeys - 1] = PointerGetDatum(stxkeys);
+   nulls[Anum_pg_statistic_ext_stxstattarget - 1] = true;
    values[Anum_pg_statistic_ext_stxkind - 1] = PointerGetDatum(stxkind);
 
    values[Anum_pg_statistic_ext_stxexprs - 1] = exprsDatum;
@@ -606,23 +606,36 @@ AlterStatistics(AlterStatsStmt *stmt)
    bool        repl_null[Natts_pg_statistic_ext];
    bool        repl_repl[Natts_pg_statistic_ext];
    ObjectAddress address;
-   int         newtarget = stmt->stxstattarget;
+   int         newtarget;
+   bool        newtarget_default;
 
-   /* Limit statistics target to a sane range */
-   if (newtarget < -1)
+   /* -1 was used in previous versions for the default setting */
+   if (stmt->stxstattarget && intVal(stmt->stxstattarget) != -1)
    {
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("statistics target %d is too low",
-                       newtarget)));
+       newtarget = intVal(stmt->stxstattarget);
+       newtarget_default = false;
    }
-   else if (newtarget > MAX_STATISTICS_TARGET)
+   else
+       newtarget_default = true;
+
+   if (!newtarget_default)
    {
-       newtarget = MAX_STATISTICS_TARGET;
-       ereport(WARNING,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("lowering statistics target to %d",
-                       newtarget)));
+       /* Limit statistics target to a sane range */
+       if (newtarget < 0)
+       {
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("statistics target %d is too low",
+                           newtarget)));
+       }
+       else if (newtarget > MAX_STATISTICS_TARGET)
+       {
+           newtarget = MAX_STATISTICS_TARGET;
+           ereport(WARNING,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("lowering statistics target to %d",
+                           newtarget)));
+       }
    }
 
    /* lookup OID of the statistics object */
@@ -673,7 +686,10 @@ AlterStatistics(AlterStatsStmt *stmt)
 
    /* replace the stxstattarget column */
    repl_repl[Anum_pg_statistic_ext_stxstattarget - 1] = true;
-   repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget);
+   if (!newtarget_default)
+       repl_val[Anum_pg_statistic_ext_stxstattarget - 1] = Int16GetDatum(newtarget);
+   else
+       repl_null[Anum_pg_statistic_ext_stxstattarget - 1] = true;
 
    newtup = heap_modify_tuple(oldtup, RelationGetDescr(rel),
                               repl_val, repl_null, repl_repl);
index 2470265561a8d820ddad21980c3d95719f6cb7f5..ae6719329e7df36e3f82fabff88321ce7438f502 100644 (file)
@@ -8712,6 +8712,7 @@ static ObjectAddress
 ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newValue, LOCKMODE lockmode)
 {
    int         newtarget;
+   bool        newtarget_default;
    Relation    attrelation;
    HeapTuple   tuple,
                newtuple;
@@ -8733,35 +8734,35 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("cannot refer to non-index column by number")));
 
-   if (newValue)
+   /* -1 was used in previous versions for the default setting */
+   if (newValue && intVal(newValue) != -1)
    {
        newtarget = intVal(newValue);
+       newtarget_default = false;
    }
    else
+       newtarget_default = true;
+
+   if (!newtarget_default)
    {
        /*
-        * -1 was used in previous versions to represent the default setting
+        * Limit target to a sane range
         */
-       newtarget = -1;
-   }
-
-   /*
-    * Limit target to a sane range
-    */
-   if (newtarget < -1)
-   {
-       ereport(ERROR,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("statistics target %d is too low",
-                       newtarget)));
-   }
-   else if (newtarget > MAX_STATISTICS_TARGET)
-   {
-       newtarget = MAX_STATISTICS_TARGET;
-       ereport(WARNING,
-               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                errmsg("lowering statistics target to %d",
-                       newtarget)));
+       if (newtarget < 0)
+       {
+           ereport(ERROR,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("statistics target %d is too low",
+                           newtarget)));
+       }
+       else if (newtarget > MAX_STATISTICS_TARGET)
+       {
+           newtarget = MAX_STATISTICS_TARGET;
+           ereport(WARNING,
+                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                    errmsg("lowering statistics target to %d",
+                           newtarget)));
+       }
    }
 
    attrelation = table_open(AttributeRelationId, RowExclusiveLock);
@@ -8815,7 +8816,7 @@ ATExecSetStatistics(Relation rel, const char *colName, int16 colNum, Node *newVa
    /* Build new tuple. */
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));
-   if (newtarget != -1)
+   if (!newtarget_default)
        repl_val[Anum_pg_attribute_attstattarget - 1] = newtarget;
    else
        repl_null[Anum_pg_attribute_attstattarget - 1] = true;
index c6e2f679fd5930072b1de5c1cdb974649c17229d..3ad99fffe1d561b90a381f7fcc496e64928af3e0 100644 (file)
@@ -4610,7 +4610,7 @@ stats_param:  ColId
  *****************************************************************************/
 
 AlterStatsStmt:
-           ALTER STATISTICS any_name SET STATISTICS SignedIconst
+           ALTER STATISTICS any_name SET STATISTICS set_statistics_value
                {
                    AlterStatsStmt *n = makeNode(AlterStatsStmt);
 
@@ -4619,7 +4619,7 @@ AlterStatsStmt:
                    n->stxstattarget = $6;
                    $$ = (Node *) n;
                }
-           | ALTER STATISTICS IF_P EXISTS any_name SET STATISTICS SignedIconst
+           | ALTER STATISTICS IF_P EXISTS any_name SET STATISTICS set_statistics_value
                {
                    AlterStatsStmt *n = makeNode(AlterStatsStmt);
 
index f21bdc2ab9a05a61ec1531c764697d2dddc56030..99fdf208dba1c4e4711755fd0a2925e27537e707 100644 (file)
@@ -454,13 +454,15 @@ fetch_statentries_for_relation(Relation pg_statext, Oid relid)
        entry->statOid = staForm->oid;
        entry->schema = get_namespace_name(staForm->stxnamespace);
        entry->name = pstrdup(NameStr(staForm->stxname));
-       entry->stattarget = staForm->stxstattarget;
        for (i = 0; i < staForm->stxkeys.dim1; i++)
        {
            entry->columns = bms_add_member(entry->columns,
                                            staForm->stxkeys.values[i]);
        }
 
+       datum = SysCacheGetAttr(STATEXTOID, htup, Anum_pg_statistic_ext_stxstattarget, &isnull);
+       entry->stattarget = isnull ? -1 : DatumGetInt16(datum);
+
        /* decode the stxkind char array into a list of chars */
        datum = SysCacheGetAttrNotNull(STATEXTOID, htup,
                                       Anum_pg_statistic_ext_stxkind);
index 171e591696596a3e263f1238729146a2c0394537..a5149ca823c9b1c4dddea2a92358d23320d3899d 100644 (file)
@@ -7580,7 +7580,7 @@ getExtendedStatistics(Archive *fout)
 
    if (fout->remoteVersion < 130000)
        appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
-                            "stxnamespace, stxowner, stxrelid, (-1) AS stxstattarget "
+                            "stxnamespace, stxowner, stxrelid, NULL AS stxstattarget "
                             "FROM pg_catalog.pg_statistic_ext");
    else
        appendPQExpBufferStr(query, "SELECT tableoid, oid, stxname, "
@@ -7613,7 +7613,10 @@ getExtendedStatistics(Archive *fout)
        statsextinfo[i].rolname = getRoleName(PQgetvalue(res, i, i_stxowner));
        statsextinfo[i].stattable =
            findTableByOid(atooid(PQgetvalue(res, i, i_stxrelid)));
-       statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
+       if (PQgetisnull(res, i, i_stattarget))
+           statsextinfo[i].stattarget = -1;
+       else
+           statsextinfo[i].stattarget = atoi(PQgetvalue(res, i, i_stattarget));
 
        /* Decide whether we want to dump it */
        selectDumpableStatisticsObject(&(statsextinfo[i]), fout);
@@ -17062,8 +17065,7 @@ dumpStatisticsExt(Archive *fout, const StatsExtInfo *statsextinfo)
 
    /*
     * We only issue an ALTER STATISTICS statement if the stxstattarget entry
-    * for this statistics object is non-negative (i.e. it's not the default
-    * value).
+    * for this statistics object is not the default value.
     */
    if (statsextinfo->stattarget >= 0)
    {
index 1ab80eb7cacc8dd60c77c8352ace2ec6cb29a925..6433497bcd20893baad82f3a0c55c3fb8570f5a7 100644 (file)
@@ -2804,7 +2804,8 @@ describeOneTableDetails(const char *schemaname,
                                      PQgetvalue(result, i, 1));
 
                    /* Show the stats target if it's not default */
-                   if (strcmp(PQgetvalue(result, i, 8), "-1") != 0)
+                   if (!PQgetisnull(result, i, 8) &&
+                       strcmp(PQgetvalue(result, i, 8), "-1") != 0)
                        appendPQExpBuffer(&buf, "; STATISTICS %s",
                                          PQgetvalue(result, i, 8));
 
index 9cf6dae3d90c94b793c349185f1482555be01b52..aec49079c123f06e3b544023b4e39aaa77484d67 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202403141
+#define CATALOG_VERSION_NO 202403171
 
 #endif
index 85064086ec5519f2fa7aa5381fe4c888c2b056b0..50a5c021edf53a54033aa8f5386e5dd4e7982806 100644 (file)
@@ -43,15 +43,15 @@ CATALOG(pg_statistic_ext,3381,StatisticExtRelationId)
                                                         * object's namespace */
 
    Oid         stxowner BKI_LOOKUP(pg_authid); /* statistics object's owner */
-   int16       stxstattarget BKI_DEFAULT(-1);  /* statistics target */
 
    /*
-    * variable-length fields start here, but we allow direct access to
-    * stxkeys
+    * variable-length/nullable fields start here, but we allow direct access
+    * to stxkeys
     */
    int2vector  stxkeys BKI_FORCE_NOT_NULL; /* array of column keys */
 
 #ifdef CATALOG_VARLEN
+   int16       stxstattarget BKI_DEFAULT(_null_) BKI_FORCE_NULL;   /* statistics target */
    char        stxkind[1] BKI_FORCE_NOT_NULL;  /* statistics kinds requested
                                                 * to build */
    pg_node_tree stxexprs;      /* A list of expression trees for stats
index aadaf67f57439d426c011cc8bfbf0a2c5760e95b..70a21df0fee7f5606c006708b3e0f87608b85c12 100644 (file)
@@ -3269,7 +3269,7 @@ typedef struct AlterStatsStmt
 {
    NodeTag     type;
    List       *defnames;       /* qualified name (list of String) */
-   int         stxstattarget;  /* statistics target */
+   Node       *stxstattarget;  /* statistics target */
    bool        missing_ok;     /* skip error if statistics object is missing */
 } AlterStatsStmt;