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,53 +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- stats_lock_check_privileges (reloid );
76-
77- /*
78- * Take RowExclusiveLock on pg_class, consistent with
79- * vac_update_relstats().
80- */
81- crel = table_open (RelationRelationId , RowExclusiveLock );
82-
83- tupdesc = RelationGetDescr (crel );
84- ctup = SearchSysCacheCopy1 (RELOID , ObjectIdGetDatum (reloid ));
85- if (!HeapTupleIsValid (ctup ))
86- {
87- ereport (elevel ,
88- (errcode (ERRCODE_OBJECT_IN_USE ),
89- errmsg ("pg_class entry for relid %u not found" , reloid )));
90- table_close (crel , RowExclusiveLock );
91- return false;
92- }
93-
94- pgcform = (Form_pg_class ) GETSTRUCT (ctup );
95-
96- /* relpages */
9773 if (!PG_ARGISNULL (RELPAGES_ARG ))
9874 {
99- int32 relpages = PG_GETARG_INT32 (RELPAGES_ARG );
75+ relpages = PG_GETARG_INT32 (RELPAGES_ARG );
10076
10177 /*
10278 * Partitioned tables may have relpages=-1. Note: for relations with
@@ -110,17 +86,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
11086 errmsg ("relpages cannot be < -1" )));
11187 result = false;
11288 }
113- else if (relpages != pgcform -> relpages )
114- {
115- replaces [ncols ] = Anum_pg_class_relpages ;
116- values [ncols ] = Int32GetDatum (relpages );
117- ncols ++ ;
118- }
89+ else
90+ update_relpages = true;
11991 }
12092
12193 if (!PG_ARGISNULL (RELTUPLES_ARG ))
12294 {
123- float reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
95+ reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
12496
12597 if (reltuples < -1.0 )
12698 {
@@ -129,18 +101,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
129101 errmsg ("reltuples cannot be < -1.0" )));
130102 result = false;
131103 }
132- else if (reltuples != pgcform -> reltuples )
133- {
134- replaces [ncols ] = Anum_pg_class_reltuples ;
135- values [ncols ] = Float4GetDatum (reltuples );
136- ncols ++ ;
137- }
138-
104+ else
105+ update_reltuples = true;
139106 }
140107
141108 if (!PG_ARGISNULL (RELALLVISIBLE_ARG ))
142109 {
143- int32 relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
110+ relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
144111
145112 if (relallvisible < 0 )
146113 {
@@ -149,23 +116,114 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
149116 errmsg ("relallvisible cannot be < 0" )));
150117 result = false;
151118 }
152- 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+ stats_lock_check_privileges (reloid );
127+
128+ /*
129+ * Take RowExclusiveLock on pg_class, consistent with
130+ * vac_update_relstats().
131+ */
132+ crel = table_open (RelationRelationId , RowExclusiveLock );
133+
134+ if (inplace )
135+ {
136+ HeapTuple ctup = NULL ;
137+ ScanKeyData key [1 ];
138+ Form_pg_class pgcform ;
139+ void * inplace_state = NULL ;
140+ bool dirty = false;
141+
142+ ScanKeyInit (& key [0 ], Anum_pg_class_oid , BTEqualStrategyNumber , F_OIDEQ ,
143+ ObjectIdGetDatum (reloid ));
144+ systable_inplace_update_begin (crel , ClassOidIndexId , true, NULL , 1 , key ,
145+ & ctup , & inplace_state );
146+ if (!HeapTupleIsValid (ctup ))
147+ elog (ERROR , "pg_class entry for relid %u vanished while updating statistics" ,
148+ reloid );
149+ pgcform = (Form_pg_class ) GETSTRUCT (ctup );
150+
151+ if (update_relpages && pgcform -> relpages != relpages )
153152 {
154- replaces [ncols ] = Anum_pg_class_relallvisible ;
155- values [ncols ] = Int32GetDatum (relallvisible );
156- ncols ++ ;
153+ pgcform -> relpages = relpages ;
154+ dirty = true;
157155 }
158- }
156+ if (update_reltuples && pgcform -> reltuples != reltuples )
157+ {
158+ pgcform -> reltuples = reltuples ;
159+ dirty = true;
160+ }
161+ if (update_relallvisible && pgcform -> relallvisible != relallvisible )
162+ {
163+ pgcform -> relallvisible = relallvisible ;
164+ dirty = true;
165+ }
166+
167+ if (dirty )
168+ systable_inplace_update_finish (inplace_state , ctup );
169+ else
170+ systable_inplace_update_cancel (inplace_state );
159171
160- /* only update pg_class if there is a meaningful change */
161- if (ncols > 0 )
172+ heap_freetuple (ctup );
173+ }
174+ else
162175 {
163- HeapTuple newtup ;
176+ TupleDesc tupdesc = RelationGetDescr (crel );
177+ HeapTuple ctup ;
178+ Form_pg_class pgcform ;
179+ int replaces [3 ] = {0 };
180+ Datum values [3 ] = {0 };
181+ bool nulls [3 ] = {0 };
182+ int nreplaces = 0 ;
183+
184+ ctup = SearchSysCache1 (RELOID , ObjectIdGetDatum (reloid ));
185+ if (!HeapTupleIsValid (ctup ))
186+ {
187+ ereport (elevel ,
188+ (errcode (ERRCODE_OBJECT_IN_USE ),
189+ errmsg ("pg_class entry for relid %u not found" , reloid )));
190+ table_close (crel , RowExclusiveLock );
191+ return false;
192+ }
193+ pgcform = (Form_pg_class ) GETSTRUCT (ctup );
194+
195+ if (update_relpages && relpages != pgcform -> relpages )
196+ {
197+ replaces [nreplaces ] = Anum_pg_class_relpages ;
198+ values [nreplaces ] = Int32GetDatum (relpages );
199+ nreplaces ++ ;
200+ }
201+
202+ if (update_reltuples && reltuples != pgcform -> reltuples )
203+ {
204+ replaces [nreplaces ] = Anum_pg_class_reltuples ;
205+ values [nreplaces ] = Float4GetDatum (reltuples );
206+ nreplaces ++ ;
207+ }
208+
209+ if (update_relallvisible && relallvisible != pgcform -> relallvisible )
210+ {
211+ replaces [nreplaces ] = Anum_pg_class_relallvisible ;
212+ values [nreplaces ] = Int32GetDatum (relallvisible );
213+ nreplaces ++ ;
214+ }
215+
216+ if (nreplaces > 0 )
217+ {
218+ HeapTuple newtup ;
219+
220+ newtup = heap_modify_tuple_by_cols (ctup , tupdesc , nreplaces ,
221+ replaces , values , nulls );
222+ CatalogTupleUpdate (crel , & newtup -> t_self , newtup );
223+ heap_freetuple (newtup );
224+ }
164225
165- newtup = heap_modify_tuple_by_cols (ctup , tupdesc , ncols , replaces , values ,
166- nulls );
167- CatalogTupleUpdate (crel , & newtup -> t_self , newtup );
168- heap_freetuple (newtup );
226+ ReleaseSysCache (ctup );
169227 }
170228
171229 /* release the lock, consistent with vac_update_relstats() */
@@ -180,7 +238,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
180238Datum
181239pg_set_relation_stats (PG_FUNCTION_ARGS )
182240{
183- relation_statistics_update (fcinfo , ERROR );
241+ relation_statistics_update (fcinfo , ERROR , false );
184242 PG_RETURN_VOID ();
185243}
186244
@@ -204,7 +262,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
204262 newfcinfo -> args [3 ].value = DEFAULT_RELALLVISIBLE ;
205263 newfcinfo -> args [3 ].isnull = false;
206264
207- relation_statistics_update (newfcinfo , ERROR );
265+ relation_statistics_update (newfcinfo , ERROR , false );
208266 PG_RETURN_VOID ();
209267}
210268
@@ -222,7 +280,7 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
222280 relarginfo , WARNING ))
223281 result = false;
224282
225- if (!relation_statistics_update (positional_fcinfo , WARNING ))
283+ if (!relation_statistics_update (positional_fcinfo , WARNING , true ))
226284 result = false;
227285
228286 PG_RETURN_BOOL (result );
0 commit comments