PostgreSQL Source Code  git master
operatorcmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * operatorcmds.c
4  *
5  * Routines for operator manipulation commands
6  *
7  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/backend/commands/operatorcmds.c
13  *
14  * DESCRIPTION
15  * The "DefineFoo" routines take the parse tree and pick out the
16  * appropriate arguments/flags, passing the results to the
17  * corresponding "FooDefine" routines (in src/catalog) that do
18  * the actual catalog-munging. These routines also verify permission
19  * of the user to execute the command.
20  *
21  * NOTES
22  * These things must be defined and committed in the following order:
23  * "create function":
24  * input/output, recv/send functions
25  * "create type":
26  * type
27  * "create operator":
28  * operators
29  *
30  *-------------------------------------------------------------------------
31  */
32 #include "postgres.h"
33 
34 #include "access/htup_details.h"
35 #include "access/table.h"
36 #include "catalog/dependency.h"
37 #include "catalog/indexing.h"
38 #include "catalog/objectaccess.h"
39 #include "catalog/pg_operator.h"
40 #include "catalog/pg_type.h"
41 #include "commands/alter.h"
42 #include "commands/defrem.h"
43 #include "miscadmin.h"
44 #include "parser/parse_func.h"
45 #include "parser/parse_oper.h"
46 #include "parser/parse_type.h"
47 #include "utils/acl.h"
48 #include "utils/builtins.h"
49 #include "utils/lsyscache.h"
50 #include "utils/rel.h"
51 #include "utils/syscache.h"
52 
53 static Oid ValidateRestrictionEstimator(List *restrictionName);
54 static Oid ValidateJoinEstimator(List *joinName);
55 
56 /*
57  * DefineOperator
58  * this function extracts all the information from the
59  * parameter list generated by the parser and then has
60  * OperatorCreate() do all the actual work.
61  *
62  * 'parameters' is a list of DefElem
63  */
65 DefineOperator(List *names, List *parameters)
66 {
67  char *oprName;
68  Oid oprNamespace;
69  AclResult aclresult;
70  bool canMerge = false; /* operator merges */
71  bool canHash = false; /* operator hashes */
72  List *functionName = NIL; /* function for operator */
73  TypeName *typeName1 = NULL; /* first type name */
74  TypeName *typeName2 = NULL; /* second type name */
75  Oid typeId1 = InvalidOid; /* types converted to OID */
76  Oid typeId2 = InvalidOid;
77  Oid rettype;
78  List *commutatorName = NIL; /* optional commutator operator name */
79  List *negatorName = NIL; /* optional negator operator name */
80  List *restrictionName = NIL; /* optional restrict. sel. function */
81  List *joinName = NIL; /* optional join sel. function */
82  Oid functionOid; /* functions converted to OID */
83  Oid restrictionOid;
84  Oid joinOid;
85  Oid typeId[2]; /* to hold left and right arg */
86  int nargs;
87  ListCell *pl;
88 
89  /* Convert list of names to a name and namespace */
90  oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
91 
92  /* Check we have creation rights in target namespace */
93  aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
94  if (aclresult != ACLCHECK_OK)
95  aclcheck_error(aclresult, OBJECT_SCHEMA,
96  get_namespace_name(oprNamespace));
97 
98  /*
99  * loop over the definition list and extract the information we need.
100  */
101  foreach(pl, parameters)
102  {
103  DefElem *defel = (DefElem *) lfirst(pl);
104 
105  if (strcmp(defel->defname, "leftarg") == 0)
106  {
107  typeName1 = defGetTypeName(defel);
108  if (typeName1->setof)
109  ereport(ERROR,
110  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
111  errmsg("SETOF type not allowed for operator argument")));
112  }
113  else if (strcmp(defel->defname, "rightarg") == 0)
114  {
115  typeName2 = defGetTypeName(defel);
116  if (typeName2->setof)
117  ereport(ERROR,
118  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
119  errmsg("SETOF type not allowed for operator argument")));
120  }
121  /* "function" and "procedure" are equivalent here */
122  else if (strcmp(defel->defname, "function") == 0)
123  functionName = defGetQualifiedName(defel);
124  else if (strcmp(defel->defname, "procedure") == 0)
125  functionName = defGetQualifiedName(defel);
126  else if (strcmp(defel->defname, "commutator") == 0)
127  commutatorName = defGetQualifiedName(defel);
128  else if (strcmp(defel->defname, "negator") == 0)
129  negatorName = defGetQualifiedName(defel);
130  else if (strcmp(defel->defname, "restrict") == 0)
131  restrictionName = defGetQualifiedName(defel);
132  else if (strcmp(defel->defname, "join") == 0)
133  joinName = defGetQualifiedName(defel);
134  else if (strcmp(defel->defname, "hashes") == 0)
135  canHash = defGetBoolean(defel);
136  else if (strcmp(defel->defname, "merges") == 0)
137  canMerge = defGetBoolean(defel);
138  /* These obsolete options are taken as meaning canMerge */
139  else if (strcmp(defel->defname, "sort1") == 0)
140  canMerge = true;
141  else if (strcmp(defel->defname, "sort2") == 0)
142  canMerge = true;
143  else if (strcmp(defel->defname, "ltcmp") == 0)
144  canMerge = true;
145  else if (strcmp(defel->defname, "gtcmp") == 0)
146  canMerge = true;
147  else
148  {
149  /* WARNING, not ERROR, for historical backwards-compatibility */
151  (errcode(ERRCODE_SYNTAX_ERROR),
152  errmsg("operator attribute \"%s\" not recognized",
153  defel->defname)));
154  }
155  }
156 
157  /*
158  * make sure we have our required definitions
159  */
160  if (functionName == NIL)
161  ereport(ERROR,
162  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
163  errmsg("operator function must be specified")));
164 
165  /* Transform type names to type OIDs */
166  if (typeName1)
167  typeId1 = typenameTypeId(NULL, typeName1);
168  if (typeName2)
169  typeId2 = typenameTypeId(NULL, typeName2);
170 
171  /*
172  * If only the right argument is missing, the user is likely trying to
173  * create a postfix operator, so give them a hint about why that does not
174  * work. But if both arguments are missing, do not mention postfix
175  * operators, as the user most likely simply neglected to mention the
176  * arguments.
177  */
178  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
179  ereport(ERROR,
180  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
181  errmsg("operator argument types must be specified")));
182  if (!OidIsValid(typeId2))
183  ereport(ERROR,
184  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
185  errmsg("operator right argument type must be specified"),
186  errdetail("Postfix operators are not supported.")));
187 
188  if (typeName1)
189  {
190  aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
191  if (aclresult != ACLCHECK_OK)
192  aclcheck_error_type(aclresult, typeId1);
193  }
194 
195  if (typeName2)
196  {
197  aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
198  if (aclresult != ACLCHECK_OK)
199  aclcheck_error_type(aclresult, typeId2);
200  }
201 
202  /*
203  * Look up the operator's underlying function.
204  */
205  if (!OidIsValid(typeId1))
206  {
207  typeId[0] = typeId2;
208  nargs = 1;
209  }
210  else if (!OidIsValid(typeId2))
211  {
212  typeId[0] = typeId1;
213  nargs = 1;
214  }
215  else
216  {
217  typeId[0] = typeId1;
218  typeId[1] = typeId2;
219  nargs = 2;
220  }
221  functionOid = LookupFuncName(functionName, nargs, typeId, false);
222 
223  /*
224  * We require EXECUTE rights for the function. This isn't strictly
225  * necessary, since EXECUTE will be checked at any attempted use of the
226  * operator, but it seems like a good idea anyway.
227  */
228  aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
229  if (aclresult != ACLCHECK_OK)
230  aclcheck_error(aclresult, OBJECT_FUNCTION,
231  NameListToString(functionName));
232 
233  rettype = get_func_rettype(functionOid);
234  aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
235  if (aclresult != ACLCHECK_OK)
236  aclcheck_error_type(aclresult, rettype);
237 
238  /*
239  * Look up restriction and join estimators if specified
240  */
241  if (restrictionName)
242  restrictionOid = ValidateRestrictionEstimator(restrictionName);
243  else
244  restrictionOid = InvalidOid;
245  if (joinName)
246  joinOid = ValidateJoinEstimator(joinName);
247  else
248  joinOid = InvalidOid;
249 
250  /*
251  * now have OperatorCreate do all the work..
252  */
253  return
254  OperatorCreate(oprName, /* operator name */
255  oprNamespace, /* namespace */
256  typeId1, /* left type id */
257  typeId2, /* right type id */
258  functionOid, /* function for operator */
259  commutatorName, /* optional commutator operator name */
260  negatorName, /* optional negator operator name */
261  restrictionOid, /* optional restrict. sel. function */
262  joinOid, /* optional join sel. function name */
263  canMerge, /* operator merges */
264  canHash); /* operator hashes */
265 }
266 
267 /*
268  * Look up a restriction estimator function ny name, and verify that it has
269  * the correct signature and we have the permissions to attach it to an
270  * operator.
271  */
272 static Oid
274 {
275  Oid typeId[4];
276  Oid restrictionOid;
277  AclResult aclresult;
278 
279  typeId[0] = INTERNALOID; /* PlannerInfo */
280  typeId[1] = OIDOID; /* operator OID */
281  typeId[2] = INTERNALOID; /* args list */
282  typeId[3] = INT4OID; /* varRelid */
283 
284  restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
285 
286  /* estimators must return float8 */
287  if (get_func_rettype(restrictionOid) != FLOAT8OID)
288  ereport(ERROR,
289  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
290  errmsg("restriction estimator function %s must return type %s",
291  NameListToString(restrictionName), "float8")));
292 
293  /* Require EXECUTE rights for the estimator */
294  aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
295  if (aclresult != ACLCHECK_OK)
296  aclcheck_error(aclresult, OBJECT_FUNCTION,
297  NameListToString(restrictionName));
298 
299  return restrictionOid;
300 }
301 
302 /*
303  * Look up a join estimator function ny name, and verify that it has the
304  * correct signature and we have the permissions to attach it to an
305  * operator.
306  */
307 static Oid
309 {
310  Oid typeId[5];
311  Oid joinOid;
312  Oid joinOid2;
313  AclResult aclresult;
314 
315  typeId[0] = INTERNALOID; /* PlannerInfo */
316  typeId[1] = OIDOID; /* operator OID */
317  typeId[2] = INTERNALOID; /* args list */
318  typeId[3] = INT2OID; /* jointype */
319  typeId[4] = INTERNALOID; /* SpecialJoinInfo */
320 
321  /*
322  * As of Postgres 8.4, the preferred signature for join estimators has 5
323  * arguments, but we still allow the old 4-argument form. Whine about
324  * ambiguity if both forms exist.
325  */
326  joinOid = LookupFuncName(joinName, 5, typeId, true);
327  joinOid2 = LookupFuncName(joinName, 4, typeId, true);
328  if (OidIsValid(joinOid))
329  {
330  if (OidIsValid(joinOid2))
331  ereport(ERROR,
332  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
333  errmsg("join estimator function %s has multiple matches",
334  NameListToString(joinName))));
335  }
336  else
337  {
338  joinOid = joinOid2;
339  /* If not found, reference the 5-argument signature in error msg */
340  if (!OidIsValid(joinOid))
341  joinOid = LookupFuncName(joinName, 5, typeId, false);
342  }
343 
344  /* estimators must return float8 */
345  if (get_func_rettype(joinOid) != FLOAT8OID)
346  ereport(ERROR,
347  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
348  errmsg("join estimator function %s must return type %s",
349  NameListToString(joinName), "float8")));
350 
351  /* Require EXECUTE rights for the estimator */
352  aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
353  if (aclresult != ACLCHECK_OK)
354  aclcheck_error(aclresult, OBJECT_FUNCTION,
355  NameListToString(joinName));
356 
357  return joinOid;
358 }
359 
360 /*
361  * Guts of operator deletion.
362  */
363 void
365 {
366  Relation relation;
367  HeapTuple tup;
368  Form_pg_operator op;
369 
370  relation = table_open(OperatorRelationId, RowExclusiveLock);
371 
372  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
373  if (!HeapTupleIsValid(tup)) /* should not happen */
374  elog(ERROR, "cache lookup failed for operator %u", operOid);
375  op = (Form_pg_operator) GETSTRUCT(tup);
376 
377  /*
378  * Reset links from commutator and negator, if any. In case of a
379  * self-commutator or self-negator, this means we have to re-fetch the
380  * updated tuple. (We could optimize away updates on the tuple we're
381  * about to drop, but it doesn't seem worth convoluting the logic for.)
382  */
383  if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
384  {
385  OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
386  if (operOid == op->oprcom || operOid == op->oprnegate)
387  {
388  ReleaseSysCache(tup);
389  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
390  if (!HeapTupleIsValid(tup)) /* should not happen */
391  elog(ERROR, "cache lookup failed for operator %u", operOid);
392  }
393  }
394 
395  CatalogTupleDelete(relation, &tup->t_self);
396 
397  ReleaseSysCache(tup);
398 
399  table_close(relation, RowExclusiveLock);
400 }
401 
402 /*
403  * AlterOperator
404  * routine implementing ALTER OPERATOR <operator> SET (option = ...).
405  *
406  * Currently, only RESTRICT and JOIN estimator functions can be changed.
407  */
410 {
411  ObjectAddress address;
412  Oid oprId;
413  Relation catalog;
414  HeapTuple tup;
415  Form_pg_operator oprForm;
416  int i;
417  ListCell *pl;
418  Datum values[Natts_pg_operator];
419  bool nulls[Natts_pg_operator];
420  bool replaces[Natts_pg_operator];
421  List *restrictionName = NIL; /* optional restrict. sel. function */
422  bool updateRestriction = false;
423  Oid restrictionOid;
424  List *joinName = NIL; /* optional join sel. function */
425  bool updateJoin = false;
426  Oid joinOid;
427 
428  /* Look up the operator */
429  oprId = LookupOperWithArgs(stmt->opername, false);
430  catalog = table_open(OperatorRelationId, RowExclusiveLock);
432  if (!HeapTupleIsValid(tup))
433  elog(ERROR, "cache lookup failed for operator %u", oprId);
434  oprForm = (Form_pg_operator) GETSTRUCT(tup);
435 
436  /* Process options */
437  foreach(pl, stmt->options)
438  {
439  DefElem *defel = (DefElem *) lfirst(pl);
440  List *param;
441 
442  if (defel->arg == NULL)
443  param = NIL; /* NONE, removes the function */
444  else
445  param = defGetQualifiedName(defel);
446 
447  if (strcmp(defel->defname, "restrict") == 0)
448  {
449  restrictionName = param;
450  updateRestriction = true;
451  }
452  else if (strcmp(defel->defname, "join") == 0)
453  {
454  joinName = param;
455  updateJoin = true;
456  }
457 
458  /*
459  * The rest of the options that CREATE accepts cannot be changed.
460  * Check for them so that we can give a meaningful error message.
461  */
462  else if (strcmp(defel->defname, "leftarg") == 0 ||
463  strcmp(defel->defname, "rightarg") == 0 ||
464  strcmp(defel->defname, "function") == 0 ||
465  strcmp(defel->defname, "procedure") == 0 ||
466  strcmp(defel->defname, "commutator") == 0 ||
467  strcmp(defel->defname, "negator") == 0 ||
468  strcmp(defel->defname, "hashes") == 0 ||
469  strcmp(defel->defname, "merges") == 0)
470  {
471  ereport(ERROR,
472  (errcode(ERRCODE_SYNTAX_ERROR),
473  errmsg("operator attribute \"%s\" cannot be changed",
474  defel->defname)));
475  }
476  else
477  ereport(ERROR,
478  (errcode(ERRCODE_SYNTAX_ERROR),
479  errmsg("operator attribute \"%s\" not recognized",
480  defel->defname)));
481  }
482 
483  /* Check permissions. Must be owner. */
484  if (!pg_oper_ownercheck(oprId, GetUserId()))
486  NameStr(oprForm->oprname));
487 
488  /*
489  * Look up restriction and join estimators if specified
490  */
491  if (restrictionName)
492  restrictionOid = ValidateRestrictionEstimator(restrictionName);
493  else
494  restrictionOid = InvalidOid;
495  if (joinName)
496  joinOid = ValidateJoinEstimator(joinName);
497  else
498  joinOid = InvalidOid;
499 
500  /* Perform additional checks, like OperatorCreate does */
501  if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
502  {
503  /* If it's not a binary op, these things mustn't be set: */
504  if (OidIsValid(joinOid))
505  ereport(ERROR,
506  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
507  errmsg("only binary operators can have join selectivity")));
508  }
509 
510  if (oprForm->oprresult != BOOLOID)
511  {
512  if (OidIsValid(restrictionOid))
513  ereport(ERROR,
514  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
515  errmsg("only boolean operators can have restriction selectivity")));
516  if (OidIsValid(joinOid))
517  ereport(ERROR,
518  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
519  errmsg("only boolean operators can have join selectivity")));
520  }
521 
522  /* Update the tuple */
523  for (i = 0; i < Natts_pg_operator; ++i)
524  {
525  values[i] = (Datum) 0;
526  replaces[i] = false;
527  nulls[i] = false;
528  }
529  if (updateRestriction)
530  {
531  replaces[Anum_pg_operator_oprrest - 1] = true;
532  values[Anum_pg_operator_oprrest - 1] = restrictionOid;
533  }
534  if (updateJoin)
535  {
536  replaces[Anum_pg_operator_oprjoin - 1] = true;
537  values[Anum_pg_operator_oprjoin - 1] = joinOid;
538  }
539 
540  tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
541  values, nulls, replaces);
542 
543  CatalogTupleUpdate(catalog, &tup->t_self, tup);
544 
545  address = makeOperatorDependencies(tup, true);
546 
547  InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
548 
549  table_close(catalog, NoLock);
550 
551  return address;
552 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:145
#define NIL
Definition: pg_list.h:65
ObjectAddress DefineOperator(List *names, List *parameters)
Definition: operatorcmds.c:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
ObjectAddress OperatorCreate(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
Definition: pg_operator.c:327
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:476
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:773
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:308
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2994
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4739
int errcode(int sqlerrcode)
Definition: elog.c:610
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:651
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1567
void RemoveOperatorById(Oid operOid)
Definition: operatorcmds.c:364
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
bool defGetBoolean(DefElem *def)
Definition: define.c:111
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
ObjectAddress AlterOperator(AlterOperatorStmt *stmt)
Definition: operatorcmds.c:409
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2103
bool setof
Definition: parsenodes.h:212
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define ACL_USAGE
Definition: parsenodes.h:82
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:273
Node * arg
Definition: parsenodes.h:734
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3101
ObjectWithArgs * opername
Definition: parsenodes.h:2978
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:654
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:214
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4587
int i
#define NameStr(name)
Definition: c.h:622
char * defname
Definition: parsenodes.h:733
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4675
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291