PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
stat_utils.c File Reference
#include "postgres.h"
#include "access/relation.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "statistics/stat_utils.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
Include dependency graph for stat_utils.c:

Go to the source code of this file.

Functions

void stats_check_required_arg (FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
 
bool stats_check_arg_array (FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
 
bool stats_check_arg_pair (FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum1, int argnum2)
 
void stats_lock_check_privileges (Oid reloid)
 
Oid stats_lookup_relid (const char *nspname, const char *relname)
 
static int get_arg_by_name (const char *argname, struct StatsArgInfo *arginfo)
 
static bool stats_check_arg_type (const char *argname, Oid argtype, Oid expectedtype)
 
bool stats_fill_fcinfo_from_arg_pairs (FunctionCallInfo pairs_fcinfo, FunctionCallInfo positional_fcinfo, struct StatsArgInfo *arginfo)
 

Function Documentation

◆ get_arg_by_name()

static int get_arg_by_name ( const char *  argname,
struct StatsArgInfo arginfo 
)
static

Definition at line 243 of file stat_utils.c.

244{
245 int argnum;
246
247 for (argnum = 0; arginfo[argnum].argname != NULL; argnum++)
248 if (pg_strcasecmp(argname, arginfo[argnum].argname) == 0)
249 return argnum;
250
252 (errmsg("unrecognized argument name: \"%s\"", argname)));
253
254 return -1;
255}
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
const char * argname
Definition: stat_utils.h:20

References StatsArgInfo::argname, ereport, errmsg(), pg_strcasecmp(), and WARNING.

Referenced by stats_fill_fcinfo_from_arg_pairs().

◆ stats_check_arg_array()

bool stats_check_arg_array ( FunctionCallInfo  fcinfo,
struct StatsArgInfo arginfo,
int  argnum 
)

Definition at line 56 of file stat_utils.c.

59{
60 ArrayType *arr;
61
62 if (PG_ARGISNULL(argnum))
63 return true;
64
66
67 if (ARR_NDIM(arr) != 1)
68 {
70 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
71 errmsg("\"%s\" cannot be a multidimensional array",
72 arginfo[argnum].argname)));
73 return false;
74 }
75
76 if (array_contains_nulls(arr))
77 {
79 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
80 errmsg("\"%s\" array cannot contain NULL values",
81 arginfo[argnum].argname)));
82 return false;
83 }
84
85 return true;
86}
#define ARR_NDIM(a)
Definition: array.h:290
#define DatumGetArrayTypeP(X)
Definition: array.h:261
bool array_contains_nulls(ArrayType *array)
Definition: arrayfuncs.c:3767
int errcode(int sqlerrcode)
Definition: elog.c:853
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268

References ARR_NDIM, array_contains_nulls(), DatumGetArrayTypeP, ereport, errcode(), errmsg(), PG_ARGISNULL, PG_GETARG_DATUM, and WARNING.

Referenced by attribute_statistics_update().

◆ stats_check_arg_pair()

bool stats_check_arg_pair ( FunctionCallInfo  fcinfo,
struct StatsArgInfo arginfo,
int  argnum1,
int  argnum2 
)

Definition at line 97 of file stat_utils.c.

100{
101 if (PG_ARGISNULL(argnum1) && PG_ARGISNULL(argnum2))
102 return true;
103
104 if (PG_ARGISNULL(argnum1) || PG_ARGISNULL(argnum2))
105 {
106 int nullarg = PG_ARGISNULL(argnum1) ? argnum1 : argnum2;
107 int otherarg = PG_ARGISNULL(argnum1) ? argnum2 : argnum1;
108
110 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
111 errmsg("\"%s\" must be specified when \"%s\" is specified",
112 arginfo[nullarg].argname,
113 arginfo[otherarg].argname)));
114
115 return false;
116 }
117
118 return true;
119}

References ereport, errcode(), errmsg(), PG_ARGISNULL, and WARNING.

Referenced by attribute_statistics_update().

◆ stats_check_arg_type()

static bool stats_check_arg_type ( const char *  argname,
Oid  argtype,
Oid  expectedtype 
)
static

Definition at line 261 of file stat_utils.c.

262{
263 if (argtype != expectedtype)
264 {
266 (errmsg("argument \"%s\" has type \"%s\", expected type \"%s\"",
267 argname, format_type_be(argtype),
268 format_type_be(expectedtype))));
269 return false;
270 }
271
272 return true;
273}
char * format_type_be(Oid type_oid)
Definition: format_type.c:343

References ereport, errmsg(), format_type_be(), and WARNING.

Referenced by stats_fill_fcinfo_from_arg_pairs().

◆ stats_check_required_arg()

void stats_check_required_arg ( FunctionCallInfo  fcinfo,
struct StatsArgInfo arginfo,
int  argnum 
)

Definition at line 37 of file stat_utils.c.

40{
41 if (PG_ARGISNULL(argnum))
43 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
44 errmsg("\"%s\" cannot be NULL",
45 arginfo[argnum].argname)));
46}
#define ERROR
Definition: elog.h:39

References ereport, errcode(), errmsg(), ERROR, and PG_ARGISNULL.

Referenced by attribute_statistics_update(), pg_clear_attribute_stats(), and relation_statistics_update().

◆ stats_fill_fcinfo_from_arg_pairs()

bool stats_fill_fcinfo_from_arg_pairs ( FunctionCallInfo  pairs_fcinfo,
FunctionCallInfo  positional_fcinfo,
struct StatsArgInfo arginfo 
)

Definition at line 285 of file stat_utils.c.

288{
289 Datum *args;
290 bool *argnulls;
291 Oid *types;
292 int nargs;
293 bool result = true;
294
295 /* clear positional args */
296 for (int i = 0; arginfo[i].argname != NULL; i++)
297 {
298 positional_fcinfo->args[i].value = (Datum) 0;
299 positional_fcinfo->args[i].isnull = true;
300 }
301
302 nargs = extract_variadic_args(pairs_fcinfo, 0, true,
303 &args, &types, &argnulls);
304
305 if (nargs % 2 != 0)
307 errmsg("variadic arguments must be name/value pairs"),
308 errhint("Provide an even number of variadic arguments that can be divided into pairs."));
309
310 /*
311 * For each argument name/value pair, find corresponding positional
312 * argument for the argument name, and assign the argument value to
313 * positional_fcinfo.
314 */
315 for (int i = 0; i < nargs; i += 2)
316 {
317 int argnum;
318 char *argname;
319
320 if (argnulls[i])
322 (errmsg("name at variadic position %d is NULL", i + 1)));
323
324 if (types[i] != TEXTOID)
326 (errmsg("name at variadic position %d has type \"%s\", expected type \"%s\"",
327 i + 1, format_type_be(types[i]),
328 format_type_be(TEXTOID))));
329
330 if (argnulls[i + 1])
331 continue;
332
333 argname = TextDatumGetCString(args[i]);
334
335 /*
336 * The 'version' argument is a special case, not handled by arginfo
337 * because it's not a valid positional argument.
338 *
339 * For now, 'version' is accepted but ignored. In the future it can be
340 * used to interpret older statistics properly.
341 */
342 if (pg_strcasecmp(argname, "version") == 0)
343 continue;
344
345 argnum = get_arg_by_name(argname, arginfo);
346
347 if (argnum < 0 || !stats_check_arg_type(argname, types[i + 1],
348 arginfo[argnum].argtype))
349 {
350 result = false;
351 continue;
352 }
353
354 positional_fcinfo->args[argnum].value = args[i + 1];
355 positional_fcinfo->args[argnum].isnull = false;
356 }
357
358 return result;
359}
#define TextDatumGetCString(d)
Definition: builtins.h:98
struct typedefs * types
Definition: ecpg.c:30
int errhint(const char *fmt,...)
Definition: elog.c:1317
int extract_variadic_args(FunctionCallInfo fcinfo, int variadic_start, bool convert_unknown, Datum **args, Oid **types, bool **nulls)
Definition: funcapi.c:2005
int i
Definition: isn.c:77
uintptr_t Datum
Definition: postgres.h:69
unsigned int Oid
Definition: postgres_ext.h:30
static int get_arg_by_name(const char *argname, struct StatsArgInfo *arginfo)
Definition: stat_utils.c:243
static bool stats_check_arg_type(const char *argname, Oid argtype, Oid expectedtype)
Definition: stat_utils.c:261
NullableDatum args[FLEXIBLE_ARRAY_MEMBER]
Definition: fmgr.h:95
Datum value
Definition: postgres.h:80
bool isnull
Definition: postgres.h:82

References StatsArgInfo::argname, generate_unaccent_rules::args, FunctionCallInfoBaseData::args, ereport, errhint(), errmsg(), ERROR, extract_variadic_args(), format_type_be(), get_arg_by_name(), i, NullableDatum::isnull, pg_strcasecmp(), stats_check_arg_type(), TextDatumGetCString, types, and NullableDatum::value.

Referenced by pg_restore_attribute_stats(), and pg_restore_relation_stats().

◆ stats_lock_check_privileges()

void stats_lock_check_privileges ( Oid  reloid)

Definition at line 131 of file stat_utils.c.

132{
134 Oid table_oid = reloid;
135 Oid index_oid = InvalidOid;
136 LOCKMODE index_lockmode = NoLock;
137
138 /*
139 * For indexes, we follow the locking behavior in do_analyze_rel() and
140 * check_lock_if_inplace_updateable_rel(), which is to lock the table
141 * first in ShareUpdateExclusive mode and then the index in AccessShare
142 * mode.
143 *
144 * Partitioned indexes are treated differently than normal indexes in
145 * check_lock_if_inplace_updateable_rel(), so we take a
146 * ShareUpdateExclusive lock on both the partitioned table and the
147 * partitioned index.
148 */
149 switch (get_rel_relkind(reloid))
150 {
151 case RELKIND_INDEX:
152 index_oid = reloid;
153 table_oid = IndexGetRelation(index_oid, false);
154 index_lockmode = AccessShareLock;
155 break;
156 case RELKIND_PARTITIONED_INDEX:
157 index_oid = reloid;
158 table_oid = IndexGetRelation(index_oid, false);
159 index_lockmode = ShareUpdateExclusiveLock;
160 break;
161 default:
162 break;
163 }
164
166
167 /* the relkinds that can be used with ANALYZE */
168 switch (table->rd_rel->relkind)
169 {
170 case RELKIND_RELATION:
171 case RELKIND_MATVIEW:
172 case RELKIND_FOREIGN_TABLE:
173 case RELKIND_PARTITIONED_TABLE:
174 break;
175 default:
177 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
178 errmsg("cannot modify statistics for relation \"%s\"",
180 errdetail_relkind_not_supported(table->rd_rel->relkind)));
181 }
182
183 if (OidIsValid(index_oid))
184 {
186
187 Assert(index_lockmode != NoLock);
188 index = relation_open(index_oid, index_lockmode);
189
190 Assert(index->rd_index && index->rd_index->indrelid == table_oid);
191
192 /* retain lock on index */
194 }
195
196 if (table->rd_rel->relisshared)
198 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
199 errmsg("cannot modify statistics for shared relation")));
200
201 if (!object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()))
202 {
204 GetUserId(),
206
207 if (aclresult != ACLCHECK_OK)
208 aclcheck_error(aclresult,
209 get_relkind_objtype(table->rd_rel->relkind),
210 NameStr(table->rd_rel->relname));
211 }
212
213 /* retain lock on table */
215}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2639
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4075
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4024
#define NameStr(name)
Definition: c.h:717
#define OidIsValid(objectId)
Definition: c.h:746
Oid MyDatabaseId
Definition: globals.c:94
Assert(PointerIsAligned(start, uint64))
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3583
int LOCKMODE
Definition: lockdefs.h:26
#define NoLock
Definition: lockdefs.h:34
#define AccessShareLock
Definition: lockdefs.h:36
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2086
Oid GetUserId(void)
Definition: miscinit.c:520
ObjectType get_relkind_objtype(char relkind)
#define ACL_MAINTAIN
Definition: parsenodes.h:90
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
static const struct lconv_member_info table[]
#define InvalidOid
Definition: postgres_ext.h:35
#define RelationGetRelid(relation)
Definition: rel.h:516
#define RelationGetRelationName(relation)
Definition: rel.h:550
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Definition: type.h:96

References AccessShareLock, ACL_MAINTAIN, aclcheck_error(), ACLCHECK_OK, Assert(), ereport, errcode(), errdetail_relkind_not_supported(), errmsg(), ERROR, get_rel_relkind(), get_relkind_objtype(), GetUserId(), IndexGetRelation(), InvalidOid, MyDatabaseId, NameStr, NoLock, object_ownercheck(), OidIsValid, pg_class_aclcheck(), relation_close(), relation_open(), RelationGetRelationName, RelationGetRelid, ShareUpdateExclusiveLock, and table.

Referenced by attribute_statistics_update(), pg_clear_attribute_stats(), and relation_statistics_update().

◆ stats_lookup_relid()

Oid stats_lookup_relid ( const char *  nspname,
const char *  relname 
)

Definition at line 221 of file stat_utils.c.

222{
223 Oid nspoid;
224 Oid reloid;
225
226 nspoid = LookupExplicitNamespace(nspname, false);
227 reloid = get_relname_relid(relname, nspoid);
228 if (!OidIsValid(reloid))
231 errmsg("relation \"%s.%s\" does not exist",
232 nspname, relname)));
233
234 return reloid;
235}
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1968
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3385
NameData relname
Definition: pg_class.h:38
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79

References ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, get_relname_relid(), LookupExplicitNamespace(), OidIsValid, and relname.

Referenced by attribute_statistics_update(), pg_clear_attribute_stats(), and relation_statistics_update().