2020#include "access/heapam.h"
2121#include "catalog/indexing.h"
2222#include "statistics/stat_utils.h"
23+ #include "utils/fmgroids.h"
2324#include "utils/fmgrprotos.h"
2425#include "utils/syscache.h"
2526
@@ -50,59 +51,28 @@ static struct StatsArgInfo relarginfo[] =
5051 [NUM_RELATION_STATS_ARGS ] = {0 }
5152};
5253
53- static bool relation_statistics_update (FunctionCallInfo fcinfo , int elevel );
54+ static bool relation_statistics_update (FunctionCallInfo fcinfo , int elevel ,
55+ bool inplace );
5456
5557/*
5658 * Internal function for modifying statistics for a relation.
5759 */
5860static bool
59- relation_statistics_update (FunctionCallInfo fcinfo , int elevel )
61+ relation_statistics_update (FunctionCallInfo fcinfo , int elevel , bool inplace )
6062{
6163 Oid reloid ;
6264 Relation crel ;
63- HeapTuple ctup ;
64- Form_pg_class pgcform ;
65- int replaces [3 ] = {0 };
66- Datum values [3 ] = {0 };
67- bool nulls [3 ] = {0 };
68- int ncols = 0 ;
69- TupleDesc tupdesc ;
65+ int32 relpages = DEFAULT_RELPAGES ;
66+ bool update_relpages = false;
67+ float reltuples = DEFAULT_RELTUPLES ;
68+ bool update_reltuples = false;
69+ int32 relallvisible = DEFAULT_RELALLVISIBLE ;
70+ bool update_relallvisible = false;
7071 bool result = true;
7172
72- stats_check_required_arg (fcinfo , relarginfo , RELATION_ARG );
73- reloid = PG_GETARG_OID (RELATION_ARG );
74-
75- if (RecoveryInProgress ())
76- ereport (ERROR ,
77- (errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
78- errmsg ("recovery is in progress" ),
79- errhint ("Statistics cannot be modified during recovery." )));
80-
81- stats_lock_check_privileges (reloid );
82-
83- /*
84- * Take RowExclusiveLock on pg_class, consistent with
85- * vac_update_relstats().
86- */
87- crel = table_open (RelationRelationId , RowExclusiveLock );
88-
89- tupdesc = RelationGetDescr (crel );
90- ctup = SearchSysCacheCopy1 (RELOID , ObjectIdGetDatum (reloid ));
91- if (!HeapTupleIsValid (ctup ))
92- {
93- ereport (elevel ,
94- (errcode (ERRCODE_OBJECT_IN_USE ),
95- errmsg ("pg_class entry for relid %u not found" , reloid )));
96- table_close (crel , RowExclusiveLock );
97- return false;
98- }
99-
100- pgcform = (Form_pg_class ) GETSTRUCT (ctup );
101-
102- /* relpages */
10373 if (!PG_ARGISNULL (RELPAGES_ARG ))
10474 {
105- int32 relpages = PG_GETARG_INT32 (RELPAGES_ARG );
75+ relpages = PG_GETARG_INT32 (RELPAGES_ARG );
10676
10777 /*
10878 * Partitioned tables may have relpages=-1. Note: for relations with
@@ -116,17 +86,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
11686 errmsg ("relpages cannot be < -1" )));
11787 result = false;
11888 }
119- else if (relpages != pgcform -> relpages )
120- {
121- replaces [ncols ] = Anum_pg_class_relpages ;
122- values [ncols ] = Int32GetDatum (relpages );
123- ncols ++ ;
124- }
89+ else
90+ update_relpages = true;
12591 }
12692
12793 if (!PG_ARGISNULL (RELTUPLES_ARG ))
12894 {
129- float reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
95+ reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
13096
13197 if (reltuples < -1.0 )
13298 {
@@ -135,18 +101,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
135101 errmsg ("reltuples cannot be < -1.0" )));
136102 result = false;
137103 }
138- else if (reltuples != pgcform -> reltuples )
139- {
140- replaces [ncols ] = Anum_pg_class_reltuples ;
141- values [ncols ] = Float4GetDatum (reltuples );
142- ncols ++ ;
143- }
144-
104+ else
105+ update_reltuples = true;
145106 }
146107
147108 if (!PG_ARGISNULL (RELALLVISIBLE_ARG ))
148109 {
149- int32 relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
110+ relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
150111
151112 if (relallvisible < 0 )
152113 {
@@ -155,23 +116,120 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
155116 errmsg ("relallvisible cannot be < 0" )));
156117 result = false;
157118 }
158- else if (relallvisible != pgcform -> relallvisible )
119+ else
120+ update_relallvisible = true;
121+ }
122+
123+ stats_check_required_arg (fcinfo , relarginfo , RELATION_ARG );
124+ reloid = PG_GETARG_OID (RELATION_ARG );
125+
126+ if (RecoveryInProgress ())
127+ ereport (ERROR ,
128+ (errcode (ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ),
129+ errmsg ("recovery is in progress" ),
130+ errhint ("Statistics cannot be modified during recovery." )));
131+
132+ stats_lock_check_privileges (reloid );
133+
134+ /*
135+ * Take RowExclusiveLock on pg_class, consistent with
136+ * vac_update_relstats().
137+ */
138+ crel = table_open (RelationRelationId , RowExclusiveLock );
139+
140+ if (inplace )
141+ {
142+ HeapTuple ctup = NULL ;
143+ ScanKeyData key [1 ];
144+ Form_pg_class pgcform ;
145+ void * inplace_state = NULL ;
146+ bool dirty = false;
147+
148+ ScanKeyInit (& key [0 ], Anum_pg_class_oid , BTEqualStrategyNumber , F_OIDEQ ,
149+ ObjectIdGetDatum (reloid ));
150+ systable_inplace_update_begin (crel , ClassOidIndexId , true, NULL , 1 , key ,
151+ & ctup , & inplace_state );
152+ if (!HeapTupleIsValid (ctup ))
153+ elog (ERROR , "pg_class entry for relid %u vanished while updating statistics" ,
154+ reloid );
155+ pgcform = (Form_pg_class ) GETSTRUCT (ctup );
156+
157+ if (update_relpages && pgcform -> relpages != relpages )
159158 {
160- replaces [ncols ] = Anum_pg_class_relallvisible ;
161- values [ncols ] = Int32GetDatum (relallvisible );
162- ncols ++ ;
159+ pgcform -> relpages = relpages ;
160+ dirty = true;
163161 }
164- }
162+ if (update_reltuples && pgcform -> reltuples != reltuples )
163+ {
164+ pgcform -> reltuples = reltuples ;
165+ dirty = true;
166+ }
167+ if (update_relallvisible && pgcform -> relallvisible != relallvisible )
168+ {
169+ pgcform -> relallvisible = relallvisible ;
170+ dirty = true;
171+ }
172+
173+ if (dirty )
174+ systable_inplace_update_finish (inplace_state , ctup );
175+ else
176+ systable_inplace_update_cancel (inplace_state );
165177
166- /* only update pg_class if there is a meaningful change */
167- if (ncols > 0 )
178+ heap_freetuple (ctup );
179+ }
180+ else
168181 {
169- HeapTuple newtup ;
182+ TupleDesc tupdesc = RelationGetDescr (crel );
183+ HeapTuple ctup ;
184+ Form_pg_class pgcform ;
185+ int replaces [3 ] = {0 };
186+ Datum values [3 ] = {0 };
187+ bool nulls [3 ] = {0 };
188+ int nreplaces = 0 ;
189+
190+ ctup = SearchSysCache1 (RELOID , ObjectIdGetDatum (reloid ));
191+ if (!HeapTupleIsValid (ctup ))
192+ {
193+ ereport (elevel ,
194+ (errcode (ERRCODE_OBJECT_IN_USE ),
195+ errmsg ("pg_class entry for relid %u not found" , reloid )));
196+ table_close (crel , RowExclusiveLock );
197+ return false;
198+ }
199+ pgcform = (Form_pg_class ) GETSTRUCT (ctup );
200+
201+ if (update_relpages && relpages != pgcform -> relpages )
202+ {
203+ replaces [nreplaces ] = Anum_pg_class_relpages ;
204+ values [nreplaces ] = Int32GetDatum (relpages );
205+ nreplaces ++ ;
206+ }
207+
208+ if (update_reltuples && reltuples != pgcform -> reltuples )
209+ {
210+ replaces [nreplaces ] = Anum_pg_class_reltuples ;
211+ values [nreplaces ] = Float4GetDatum (reltuples );
212+ nreplaces ++ ;
213+ }
214+
215+ if (update_relallvisible && relallvisible != pgcform -> relallvisible )
216+ {
217+ replaces [nreplaces ] = Anum_pg_class_relallvisible ;
218+ values [nreplaces ] = Int32GetDatum (relallvisible );
219+ nreplaces ++ ;
220+ }
221+
222+ if (nreplaces > 0 )
223+ {
224+ HeapTuple newtup ;
225+
226+ newtup = heap_modify_tuple_by_cols (ctup , tupdesc , nreplaces ,
227+ replaces , values , nulls );
228+ CatalogTupleUpdate (crel , & newtup -> t_self , newtup );
229+ heap_freetuple (newtup );
230+ }
170231
171- newtup = heap_modify_tuple_by_cols (ctup , tupdesc , ncols , replaces , values ,
172- nulls );
173- CatalogTupleUpdate (crel , & newtup -> t_self , newtup );
174- heap_freetuple (newtup );
232+ ReleaseSysCache (ctup );
175233 }
176234
177235 /* release the lock, consistent with vac_update_relstats() */
@@ -188,7 +246,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
188246Datum
189247pg_set_relation_stats (PG_FUNCTION_ARGS )
190248{
191- relation_statistics_update (fcinfo , ERROR );
249+ relation_statistics_update (fcinfo , ERROR , false );
192250 PG_RETURN_VOID ();
193251}
194252
@@ -212,7 +270,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
212270 newfcinfo -> args [3 ].value = DEFAULT_RELALLVISIBLE ;
213271 newfcinfo -> args [3 ].isnull = false;
214272
215- relation_statistics_update (newfcinfo , ERROR );
273+ relation_statistics_update (newfcinfo , ERROR , false );
216274 PG_RETURN_VOID ();
217275}
218276
@@ -230,7 +288,7 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
230288 relarginfo , WARNING ))
231289 result = false;
232290
233- if (!relation_statistics_update (positional_fcinfo , WARNING ))
291+ if (!relation_statistics_update (positional_fcinfo , WARNING , true ))
234292 result = false;
235293
236294 PG_RETURN_BOOL (result );
0 commit comments