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;