PostgreSQL Source Code  git master
stat_utils.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  * stat_utils.c
3  *
4  * PostgreSQL statistics manipulation utilities.
5  *
6  * Code supporting the direct manipulation of statistics.
7  *
8  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  * IDENTIFICATION
12  * src/backend/statistics/stat_utils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 #include "postgres.h"
18 
19 #include "access/relation.h"
20 #include "catalog/pg_database.h"
21 #include "miscadmin.h"
22 #include "statistics/stat_utils.h"
23 #include "utils/acl.h"
24 #include "utils/array.h"
25 #include "utils/builtins.h"
26 #include "utils/rel.h"
27 
28 /*
29  * Ensure that a given argument is not null.
30  */
31 void
33  struct StatsArgInfo *arginfo,
34  int argnum)
35 {
36  if (PG_ARGISNULL(argnum))
37  ereport(ERROR,
38  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
39  errmsg("\"%s\" cannot be NULL",
40  arginfo[argnum].argname)));
41 }
42 
43 /*
44  * Check that argument is either NULL or a one dimensional array with no
45  * NULLs.
46  *
47  * If a problem is found, emit at elevel, and return false. Otherwise return
48  * true.
49  */
50 bool
52  struct StatsArgInfo *arginfo,
53  int argnum, int elevel)
54 {
55  ArrayType *arr;
56 
57  if (PG_ARGISNULL(argnum))
58  return true;
59 
60  arr = DatumGetArrayTypeP(PG_GETARG_DATUM(argnum));
61 
62  if (ARR_NDIM(arr) != 1)
63  {
64  ereport(elevel,
65  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
66  errmsg("\"%s\" cannot be a multidimensional array",
67  arginfo[argnum].argname)));
68  return false;
69  }
70 
71  if (array_contains_nulls(arr))
72  {
73  ereport(elevel,
74  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
75  errmsg("\"%s\" array cannot contain NULL values",
76  arginfo[argnum].argname)));
77  return false;
78  }
79 
80  return true;
81 }
82 
83 /*
84  * Enforce parameter pairs that must be specified together (or not at all) for
85  * a particular stakind, such as most_common_vals and most_common_freqs for
86  * STATISTIC_KIND_MCV.
87  *
88  * If a problem is found, emit at elevel, and return false. Otherwise return
89  * true.
90  */
91 bool
93  struct StatsArgInfo *arginfo,
94  int argnum1, int argnum2, int elevel)
95 {
96  if (PG_ARGISNULL(argnum1) && PG_ARGISNULL(argnum2))
97  return true;
98 
99  if (PG_ARGISNULL(argnum1) || PG_ARGISNULL(argnum2))
100  {
101  int nullarg = PG_ARGISNULL(argnum1) ? argnum1 : argnum2;
102  int otherarg = PG_ARGISNULL(argnum1) ? argnum2 : argnum1;
103 
104  ereport(elevel,
105  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
106  errmsg("\"%s\" must be specified when \"%s\" is specified",
107  arginfo[nullarg].argname,
108  arginfo[otherarg].argname)));
109 
110  return false;
111  }
112 
113  return true;
114 }
115 
116 /*
117  * Lock relation in ShareUpdateExclusive mode, check privileges, and close the
118  * relation (but retain the lock).
119  *
120  * A role has privileges to set statistics on the relation if any of the
121  * following are true:
122  * - the role owns the current database and the relation is not shared
123  * - the role has the MAINTAIN privilege on the relation
124  */
125 void
127 {
129  const char relkind = rel->rd_rel->relkind;
130 
131  /* All of the types that can be used with ANALYZE, plus indexes */
132  switch (relkind)
133  {
134  case RELKIND_RELATION:
135  case RELKIND_INDEX:
136  case RELKIND_MATVIEW:
137  case RELKIND_FOREIGN_TABLE:
138  case RELKIND_PARTITIONED_TABLE:
139  case RELKIND_PARTITIONED_INDEX:
140  break;
141  default:
142  ereport(ERROR,
143  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
144  errmsg("cannot modify statistics for relation \"%s\"",
146  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
147  }
148 
149  if (rel->rd_rel->relisshared)
150  ereport(ERROR,
151  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
152  errmsg("cannot modify statistics for shared relation")));
153 
154  if (!object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()))
155  {
157  GetUserId(),
158  ACL_MAINTAIN);
159 
160  if (aclresult != ACLCHECK_OK)
161  aclcheck_error(aclresult,
162  get_relkind_objtype(rel->rd_rel->relkind),
163  NameStr(rel->rd_rel->relname));
164  }
165 
166  relation_close(rel, NoLock);
167 }
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2703
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4094
#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
#define NameStr(name)
Definition: c.h:737
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
Oid MyDatabaseId
Definition: globals.c:93
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
Oid GetUserId(void)
Definition: miscinit.c:514
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
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetRelid(relation)
Definition: rel.h:505
#define RelationGetRelationName(relation)
Definition: rel.h:539
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
bool stats_check_arg_array(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum, int elevel)
Definition: stat_utils.c:51
void stats_check_required_arg(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum)
Definition: stat_utils.c:32
bool stats_check_arg_pair(FunctionCallInfo fcinfo, struct StatsArgInfo *arginfo, int argnum1, int argnum2, int elevel)
Definition: stat_utils.c:92
void stats_lock_check_privileges(Oid reloid)
Definition: stat_utils.c:126
Form_pg_class rd_rel
Definition: rel.h:111