PostgreSQL Source Code  git master
relation_stats.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  * relation_stats.c
3  *
4  * PostgreSQL relation statistics manipulation
5  *
6  * Code supporting the direct import of relation statistics, similar to
7  * what is done by the ANALYZE command.
8  *
9  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  * IDENTIFICATION
13  * src/backend/statistics/relation_stats.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 
18 #include "postgres.h"
19 
20 #include "access/heapam.h"
21 #include "catalog/indexing.h"
22 #include "statistics/stat_utils.h"
23 #include "utils/fmgroids.h"
24 #include "utils/fmgrprotos.h"
25 #include "utils/syscache.h"
26 
27 #define DEFAULT_RELPAGES Int32GetDatum(0)
28 #define DEFAULT_RELTUPLES Float4GetDatum(-1.0)
29 #define DEFAULT_RELALLVISIBLE Int32GetDatum(0)
30 
31 /*
32  * Positional argument numbers, names, and types for
33  * relation_statistics_update().
34  */
35 
37 {
43 };
44 
45 static struct StatsArgInfo relarginfo[] =
46 {
47  [RELATION_ARG] = {"relation", REGCLASSOID},
48  [RELPAGES_ARG] = {"relpages", INT4OID},
49  [RELTUPLES_ARG] = {"reltuples", FLOAT4OID},
50  [RELALLVISIBLE_ARG] = {"relallvisible", INT4OID},
52 };
53 
54 static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel,
55  bool inplace);
56 
57 /*
58  * Internal function for modifying statistics for a relation.
59  */
60 static bool
61 relation_statistics_update(FunctionCallInfo fcinfo, int elevel, bool inplace)
62 {
63  Oid reloid;
64  Relation crel;
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;
71  bool result = true;
72 
74  {
75  relpages = PG_GETARG_INT32(RELPAGES_ARG);
76 
77  /*
78  * Partitioned tables may have relpages=-1. Note: for relations with
79  * no storage, relpages=-1 is not used consistently, but must be
80  * supported here.
81  */
82  if (relpages < -1)
83  {
84  ereport(elevel,
85  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
86  errmsg("relpages cannot be < -1")));
87  result = false;
88  }
89  else
90  update_relpages = true;
91  }
92 
94  {
95  reltuples = PG_GETARG_FLOAT4(RELTUPLES_ARG);
96 
97  if (reltuples < -1.0)
98  {
99  ereport(elevel,
100  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101  errmsg("reltuples cannot be < -1.0")));
102  result = false;
103  }
104  else
105  update_reltuples = true;
106  }
107 
109  {
110  relallvisible = PG_GETARG_INT32(RELALLVISIBLE_ARG);
111 
112  if (relallvisible < 0)
113  {
114  ereport(elevel,
115  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
116  errmsg("relallvisible cannot be < 0")));
117  result = false;
118  }
119  else
120  update_relallvisible = true;
121  }
122 
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 
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)
158  {
159  pgcform->relpages = relpages;
160  dirty = true;
161  }
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);
177 
178  heap_freetuple(ctup);
179  }
180  else
181  {
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)));
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  }
231 
232  ReleaseSysCache(ctup);
233  }
234 
235  /* release the lock, consistent with vac_update_relstats() */
237 
239 
240  return result;
241 }
242 
243 /*
244  * Set statistics for a given pg_class entry.
245  */
246 Datum
248 {
249  relation_statistics_update(fcinfo, ERROR, false);
250  PG_RETURN_VOID();
251 }
252 
253 /*
254  * Clear statistics for a given pg_class entry; that is, set back to initial
255  * stats for a newly-created table.
256  */
257 Datum
259 {
260  LOCAL_FCINFO(newfcinfo, 4);
261 
262  InitFunctionCallInfoData(*newfcinfo, NULL, 4, InvalidOid, NULL, NULL);
263 
264  newfcinfo->args[0].value = PG_GETARG_OID(0);
265  newfcinfo->args[0].isnull = PG_ARGISNULL(0);
266  newfcinfo->args[1].value = DEFAULT_RELPAGES;
267  newfcinfo->args[1].isnull = false;
268  newfcinfo->args[2].value = DEFAULT_RELTUPLES;
269  newfcinfo->args[2].isnull = false;
270  newfcinfo->args[3].value = DEFAULT_RELALLVISIBLE;
271  newfcinfo->args[3].isnull = false;
272 
273  relation_statistics_update(newfcinfo, ERROR, false);
274  PG_RETURN_VOID();
275 }
276 
277 Datum
279 {
280  LOCAL_FCINFO(positional_fcinfo, NUM_RELATION_STATS_ARGS);
281  bool result = true;
282 
283  InitFunctionCallInfoData(*positional_fcinfo, NULL,
285  InvalidOid, NULL, NULL);
286 
287  if (!stats_fill_fcinfo_from_arg_pairs(fcinfo, positional_fcinfo,
289  result = false;
290 
291  if (!relation_statistics_update(positional_fcinfo, WARNING, true))
292  result = false;
293 
294  PG_RETURN_BOOL(result);
295 }
static Datum values[MAXATTR]
Definition: bootstrap.c:151
int32_t int32
Definition: c.h:481
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo)
Definition: fmgr.h:150
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define LOCAL_FCINFO(name, nargs)
Definition: fmgr.h:110
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:281
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
void systable_inplace_update_cancel(void *state)
Definition: genam.c:905
void systable_inplace_update_begin(Relation relation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, const ScanKeyData *key, HeapTuple *oldtupcopy, void **state)
Definition: genam.c:810
void systable_inplace_update_finish(void *state, HeapTuple tuple)
Definition: genam.c:886
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, const int *replCols, const Datum *replValues, const bool *replIsnull)
Definition: heaptuple.c:1277
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
static Datum Float4GetDatum(float4 X)
Definition: postgres.h:475
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
static struct StatsArgInfo relarginfo[]
relation_stats_argnum
@ RELALLVISIBLE_ARG
@ RELATION_ARG
@ RELPAGES_ARG
@ RELTUPLES_ARG
@ NUM_RELATION_STATS_ARGS
#define DEFAULT_RELTUPLES
Datum pg_restore_relation_stats(PG_FUNCTION_ARGS)
#define DEFAULT_RELALLVISIBLE
static bool relation_statistics_update(FunctionCallInfo fcinfo, int elevel, bool inplace)
#define DEFAULT_RELPAGES
Datum pg_set_relation_stats(PG_FUNCTION_ARGS)
Datum pg_clear_relation_stats(PG_FUNCTION_ARGS)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition: stat_utils.c:33
bool stats_fill_fcinfo_from_arg_pairs(FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo, int elevel)
Definition: stat_utils.c:217
void stats_lock_check_privileges(Oid reloid)
Definition: stat_utils.c:127
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void CommandCounterIncrement(void)
Definition: xact.c:1099
bool RecoveryInProgress(void)
Definition: xlog.c:6334