On Tue, Oct 15, 2024 at 2:50 PM Corey Huinker <corey.huin...@gmail.com>
wrote:

>
> Oh, I see. It appears that there's a special case for partitioned
>> tables that sets relpages=-1 in do_analyze_rel() around line 680. It's
>> a bit inconsistent, though, because even partitioned indexes have
>> relpages=0. Furthermore, the parameter is of type BlockNumber, so
>> InvalidBlockNumber would make more sense.
>>
>> Not the cleanest code, but if the value exists, we need to be able to
>> import it.
>>
>>
> Thanks for tracking that down. I'll have a patch ready shortly.
>

Code fix with comment on why nobody expects a relpages -1. Test case to
demonstrate that relpages -1 can happen, and updated doc to reflect the new
lower bound.
From c0efe3fb2adac102e186e086bf94fb29fabba28b Mon Sep 17 00:00:00 2001
From: Corey Huinker <corey.huin...@gmail.com>
Date: Tue, 15 Oct 2024 19:09:59 -0400
Subject: [PATCH v1] Allow pg_set_relation_stats() to set relpages to -1.

While the default value for relpages is 0, if a partitioned table with
at least one child has been analyzed, then the partititoned table will
have a relpages value of -1. pg_set_relation_stats() should therefore be
able to set relpages to -1.

Add test case to demonstrate the behavior of ANALYZE on a partitioned
table with child table(s), and to demonstrate that
pg_set_relation_stats() now accepts -1.
---
 src/backend/statistics/relation_stats.c    |  8 +++--
 src/test/regress/expected/stats_import.out | 38 +++++++++++++++++++++-
 src/test/regress/sql/stats_import.sql      | 25 ++++++++++++++
 doc/src/sgml/func.sgml                     |  2 +-
 4 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/src/backend/statistics/relation_stats.c b/src/backend/statistics/relation_stats.c
index 26f15061e8..b90f70b190 100644
--- a/src/backend/statistics/relation_stats.c
+++ b/src/backend/statistics/relation_stats.c
@@ -99,11 +99,15 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
 	{
 		int32		relpages = PG_GETARG_INT32(RELPAGES_ARG);
 
-		if (relpages < 0)
+		/*
+		 * While the default value for relpages is 0, a partitioned table with at
+		 * least one child partition can have a relpages of -1.
+		 */
+		if (relpages < -1)
 		{
 			ereport(elevel,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("relpages cannot be < 0")));
+					 errmsg("relpages cannot be < -1")));
 			table_close(crel, RowExclusiveLock);
 			return false;
 		}
diff --git a/src/test/regress/expected/stats_import.out b/src/test/regress/expected/stats_import.out
index cd1b80aa43..46e45a5fa3 100644
--- a/src/test/regress/expected/stats_import.out
+++ b/src/test/regress/expected/stats_import.out
@@ -135,9 +135,45 @@ SELECT
         'stats_import.testview'::regclass);
 ERROR:  cannot modify statistics for relation "testview"
 DETAIL:  This operation is not supported for views.
+-- Partitioned tables with at least 1 child partition will, when analyzed,
+-- have a relpages of -1
+CREATE TABLE stats_import.part_parent ( i integer ) PARTITION BY RANGE(i);
+CREATE TABLE stats_import.part_child_1
+  PARTITION OF stats_import.part_parent
+  FOR VALUES FROM (0) TO (10);
+ANALYZE stats_import.part_parent;
+SELECT relpages
+FROM pg_class
+WHERE oid = 'stats_import.part_parent'::regclass;
+ relpages 
+----------
+       -1
+(1 row)
+
+-- nothing stops us from setting it to not -1
+SELECT
+    pg_catalog.pg_set_relation_stats(
+        relation => 'stats_import.part_parent'::regclass,
+        relpages => 2::integer);
+ pg_set_relation_stats 
+-----------------------
+ t
+(1 row)
+
+-- nothing stops us from setting it to -1
+SELECT
+    pg_catalog.pg_set_relation_stats(
+        relation => 'stats_import.part_parent'::regclass,
+        relpages => -1::integer);
+ pg_set_relation_stats 
+-----------------------
+ t
+(1 row)
+
 DROP SCHEMA stats_import CASCADE;
-NOTICE:  drop cascades to 4 other objects
+NOTICE:  drop cascades to 5 other objects
 DETAIL:  drop cascades to type stats_import.complex_type
 drop cascades to table stats_import.test
 drop cascades to sequence stats_import.testseq
 drop cascades to view stats_import.testview
+drop cascades to table stats_import.part_parent
diff --git a/src/test/regress/sql/stats_import.sql b/src/test/regress/sql/stats_import.sql
index 3e9f6d9124..ad129b1ab9 100644
--- a/src/test/regress/sql/stats_import.sql
+++ b/src/test/regress/sql/stats_import.sql
@@ -95,4 +95,29 @@ SELECT
     pg_catalog.pg_clear_relation_stats(
         'stats_import.testview'::regclass);
 
+-- Partitioned tables with at least 1 child partition will, when analyzed,
+-- have a relpages of -1
+CREATE TABLE stats_import.part_parent ( i integer ) PARTITION BY RANGE(i);
+CREATE TABLE stats_import.part_child_1
+  PARTITION OF stats_import.part_parent
+  FOR VALUES FROM (0) TO (10);
+
+ANALYZE stats_import.part_parent;
+
+SELECT relpages
+FROM pg_class
+WHERE oid = 'stats_import.part_parent'::regclass;
+
+-- nothing stops us from setting it to not -1
+SELECT
+    pg_catalog.pg_set_relation_stats(
+        relation => 'stats_import.part_parent'::regclass,
+        relpages => 2::integer);
+
+-- nothing stops us from setting it to -1
+SELECT
+    pg_catalog.pg_set_relation_stats(
+        relation => 'stats_import.part_parent'::regclass,
+        relpages => -1::integer);
+
 DROP SCHEMA stats_import CASCADE;
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f8a0d76d12..ad663c94d7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -30197,7 +30197,7 @@ DETAIL:  Make sure pg_wal_replay_wait() isn't called within a transaction with a
         </para>
         <para>
          The value of <structfield>relpages</structfield> must be greater than
-         or equal to <literal>0</literal>,
+         or equal to <literal>-1</literal>,
          <structfield>reltuples</structfield> must be greater than or equal to
          <literal>-1.0</literal>, and <structfield>relallvisible</structfield>
          must be greater than or equal to <literal>0</literal>.
-- 
2.46.2

Reply via email to