20
20
#include "access/heapam.h"
21
21
#include "catalog/indexing.h"
22
22
#include "statistics/stat_utils.h"
23
+ #include "utils/fmgroids.h"
23
24
#include "utils/fmgrprotos.h"
24
25
#include "utils/syscache.h"
25
26
@@ -50,59 +51,28 @@ static struct StatsArgInfo relarginfo[] =
50
51
[NUM_RELATION_STATS_ARGS ] = {0 }
51
52
};
52
53
53
- static bool relation_statistics_update (FunctionCallInfo fcinfo , int elevel );
54
+ static bool relation_statistics_update (FunctionCallInfo fcinfo , int elevel ,
55
+ bool inplace );
54
56
55
57
/*
56
58
* Internal function for modifying statistics for a relation.
57
59
*/
58
60
static bool
59
- relation_statistics_update (FunctionCallInfo fcinfo , int elevel )
61
+ relation_statistics_update (FunctionCallInfo fcinfo , int elevel , bool inplace )
60
62
{
61
63
Oid reloid ;
62
64
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;
70
71
bool result = true;
71
72
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 */
103
73
if (!PG_ARGISNULL (RELPAGES_ARG ))
104
74
{
105
- int32 relpages = PG_GETARG_INT32 (RELPAGES_ARG );
75
+ relpages = PG_GETARG_INT32 (RELPAGES_ARG );
106
76
107
77
/*
108
78
* Partitioned tables may have relpages=-1. Note: for relations with
@@ -116,17 +86,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
116
86
errmsg ("relpages cannot be < -1" )));
117
87
result = false;
118
88
}
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;
125
91
}
126
92
127
93
if (!PG_ARGISNULL (RELTUPLES_ARG ))
128
94
{
129
- float reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
95
+ reltuples = PG_GETARG_FLOAT4 (RELTUPLES_ARG );
130
96
131
97
if (reltuples < -1.0 )
132
98
{
@@ -135,18 +101,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
135
101
errmsg ("reltuples cannot be < -1.0" )));
136
102
result = false;
137
103
}
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;
145
106
}
146
107
147
108
if (!PG_ARGISNULL (RELALLVISIBLE_ARG ))
148
109
{
149
- int32 relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
110
+ relallvisible = PG_GETARG_INT32 (RELALLVISIBLE_ARG );
150
111
151
112
if (relallvisible < 0 )
152
113
{
@@ -155,23 +116,120 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
155
116
errmsg ("relallvisible cannot be < 0" )));
156
117
result = false;
157
118
}
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 )
159
158
{
160
- replaces [ncols ] = Anum_pg_class_relallvisible ;
161
- values [ncols ] = Int32GetDatum (relallvisible );
162
- ncols ++ ;
159
+ pgcform -> relpages = relpages ;
160
+ dirty = true;
163
161
}
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 );
165
177
166
- /* only update pg_class if there is a meaningful change */
167
- if (ncols > 0 )
178
+ heap_freetuple (ctup );
179
+ }
180
+ else
168
181
{
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
+ }
170
231
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 );
175
233
}
176
234
177
235
/* release the lock, consistent with vac_update_relstats() */
@@ -188,7 +246,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
188
246
Datum
189
247
pg_set_relation_stats (PG_FUNCTION_ARGS )
190
248
{
191
- relation_statistics_update (fcinfo , ERROR );
249
+ relation_statistics_update (fcinfo , ERROR , false );
192
250
PG_RETURN_VOID ();
193
251
}
194
252
@@ -212,7 +270,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
212
270
newfcinfo -> args [3 ].value = DEFAULT_RELALLVISIBLE ;
213
271
newfcinfo -> args [3 ].isnull = false;
214
272
215
- relation_statistics_update (newfcinfo , ERROR );
273
+ relation_statistics_update (newfcinfo , ERROR , false );
216
274
PG_RETURN_VOID ();
217
275
}
218
276
@@ -230,7 +288,7 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
230
288
relarginfo , WARNING ))
231
289
result = false;
232
290
233
- if (!relation_statistics_update (positional_fcinfo , WARNING ))
291
+ if (!relation_statistics_update (positional_fcinfo , WARNING , true ))
234
292
result = false;
235
293
236
294
PG_RETURN_BOOL (result );
0 commit comments