PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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 procedures
25  * "create type":
26  * type
27  * "create operator":
28  * operators
29  *
30  * Most of the parse-tree manipulation routines are defined in
31  * commands/manip.c.
32  *
33  *-------------------------------------------------------------------------
34  */
35 #include "postgres.h"
36 
37 #include "access/heapam.h"
38 #include "access/htup_details.h"
39 #include "catalog/dependency.h"
40 #include "catalog/indexing.h"
41 #include "catalog/objectaccess.h"
42 #include "catalog/pg_operator.h"
43 #include "catalog/pg_operator_fn.h"
44 #include "catalog/pg_type.h"
45 #include "commands/alter.h"
46 #include "commands/defrem.h"
47 #include "miscadmin.h"
48 #include "parser/parse_func.h"
49 #include "parser/parse_oper.h"
50 #include "parser/parse_type.h"
51 #include "utils/builtins.h"
52 #include "utils/lsyscache.h"
53 #include "utils/rel.h"
54 #include "utils/syscache.h"
55 
56 static Oid ValidateRestrictionEstimator(List *restrictionName);
57 static Oid ValidateJoinEstimator(List *joinName);
58 
59 /*
60  * DefineOperator
61  * this function extracts all the information from the
62  * parameter list generated by the parser and then has
63  * OperatorCreate() do all the actual work.
64  *
65  * 'parameters' is a list of DefElem
66  */
68 DefineOperator(List *names, List *parameters)
69 {
70  char *oprName;
71  Oid oprNamespace;
72  AclResult aclresult;
73  bool canMerge = false; /* operator merges */
74  bool canHash = false; /* operator hashes */
75  List *functionName = NIL; /* function for operator */
76  TypeName *typeName1 = NULL; /* first type name */
77  TypeName *typeName2 = NULL; /* second type name */
78  Oid typeId1 = InvalidOid; /* types converted to OID */
79  Oid typeId2 = InvalidOid;
80  Oid rettype;
81  List *commutatorName = NIL; /* optional commutator operator name */
82  List *negatorName = NIL; /* optional negator operator name */
83  List *restrictionName = NIL; /* optional restrict. sel. procedure */
84  List *joinName = NIL; /* optional join sel. procedure */
85  Oid functionOid; /* functions converted to OID */
86  Oid restrictionOid;
87  Oid joinOid;
88  Oid typeId[2]; /* to hold left and right arg */
89  int nargs;
90  ListCell *pl;
91 
92  /* Convert list of names to a name and namespace */
93  oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
94 
95  /* Check we have creation rights in target namespace */
96  aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
97  if (aclresult != ACLCHECK_OK)
99  get_namespace_name(oprNamespace));
100 
101  /*
102  * loop over the definition list and extract the information we need.
103  */
104  foreach(pl, parameters)
105  {
106  DefElem *defel = (DefElem *) lfirst(pl);
107 
108  if (pg_strcasecmp(defel->defname, "leftarg") == 0)
109  {
110  typeName1 = defGetTypeName(defel);
111  if (typeName1->setof)
112  ereport(ERROR,
113  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
114  errmsg("SETOF type not allowed for operator argument")));
115  }
116  else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
117  {
118  typeName2 = defGetTypeName(defel);
119  if (typeName2->setof)
120  ereport(ERROR,
121  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
122  errmsg("SETOF type not allowed for operator argument")));
123  }
124  else if (pg_strcasecmp(defel->defname, "procedure") == 0)
125  functionName = defGetQualifiedName(defel);
126  else if (pg_strcasecmp(defel->defname, "commutator") == 0)
127  commutatorName = defGetQualifiedName(defel);
128  else if (pg_strcasecmp(defel->defname, "negator") == 0)
129  negatorName = defGetQualifiedName(defel);
130  else if (pg_strcasecmp(defel->defname, "restrict") == 0)
131  restrictionName = defGetQualifiedName(defel);
132  else if (pg_strcasecmp(defel->defname, "join") == 0)
133  joinName = defGetQualifiedName(defel);
134  else if (pg_strcasecmp(defel->defname, "hashes") == 0)
135  canHash = defGetBoolean(defel);
136  else if (pg_strcasecmp(defel->defname, "merges") == 0)
137  canMerge = defGetBoolean(defel);
138  /* These obsolete options are taken as meaning canMerge */
139  else if (pg_strcasecmp(defel->defname, "sort1") == 0)
140  canMerge = true;
141  else if (pg_strcasecmp(defel->defname, "sort2") == 0)
142  canMerge = true;
143  else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
144  canMerge = true;
145  else if (pg_strcasecmp(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 procedure 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  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
172  ereport(ERROR,
173  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
174  errmsg("at least one of leftarg or rightarg must be specified")));
175 
176  if (typeName1)
177  {
178  aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
179  if (aclresult != ACLCHECK_OK)
180  aclcheck_error_type(aclresult, typeId1);
181  }
182 
183  if (typeName2)
184  {
185  aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
186  if (aclresult != ACLCHECK_OK)
187  aclcheck_error_type(aclresult, typeId2);
188  }
189 
190  /*
191  * Look up the operator's underlying function.
192  */
193  if (!OidIsValid(typeId1))
194  {
195  typeId[0] = typeId2;
196  nargs = 1;
197  }
198  else if (!OidIsValid(typeId2))
199  {
200  typeId[0] = typeId1;
201  nargs = 1;
202  }
203  else
204  {
205  typeId[0] = typeId1;
206  typeId[1] = typeId2;
207  nargs = 2;
208  }
209  functionOid = LookupFuncName(functionName, nargs, typeId, false);
210 
211  /*
212  * We require EXECUTE rights for the function. This isn't strictly
213  * necessary, since EXECUTE will be checked at any attempted use of the
214  * operator, but it seems like a good idea anyway.
215  */
216  aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
217  if (aclresult != ACLCHECK_OK)
218  aclcheck_error(aclresult, ACL_KIND_PROC,
219  NameListToString(functionName));
220 
221  rettype = get_func_rettype(functionOid);
222  aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
223  if (aclresult != ACLCHECK_OK)
224  aclcheck_error_type(aclresult, rettype);
225 
226  /*
227  * Look up restriction and join estimators if specified
228  */
229  if (restrictionName)
230  restrictionOid = ValidateRestrictionEstimator(restrictionName);
231  else
232  restrictionOid = InvalidOid;
233  if (joinName)
234  joinOid = ValidateJoinEstimator(joinName);
235  else
236  joinOid = InvalidOid;
237 
238  /*
239  * now have OperatorCreate do all the work..
240  */
241  return
242  OperatorCreate(oprName, /* operator name */
243  oprNamespace, /* namespace */
244  typeId1, /* left type id */
245  typeId2, /* right type id */
246  functionOid, /* function for operator */
247  commutatorName, /* optional commutator operator name */
248  negatorName, /* optional negator operator name */
249  restrictionOid, /* optional restrict. sel. procedure */
250  joinOid, /* optional join sel. procedure name */
251  canMerge, /* operator merges */
252  canHash); /* operator hashes */
253 }
254 
255 /*
256  * Look up a restriction estimator function ny name, and verify that it has
257  * the correct signature and we have the permissions to attach it to an
258  * operator.
259  */
260 static Oid
262 {
263  Oid typeId[4];
264  Oid restrictionOid;
265  AclResult aclresult;
266 
267  typeId[0] = INTERNALOID; /* PlannerInfo */
268  typeId[1] = OIDOID; /* operator OID */
269  typeId[2] = INTERNALOID; /* args list */
270  typeId[3] = INT4OID; /* varRelid */
271 
272  restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
273 
274  /* estimators must return float8 */
275  if (get_func_rettype(restrictionOid) != FLOAT8OID)
276  ereport(ERROR,
277  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
278  errmsg("restriction estimator function %s must return type %s",
279  NameListToString(restrictionName), "float8")));
280 
281  /* Require EXECUTE rights for the estimator */
282  aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
283  if (aclresult != ACLCHECK_OK)
284  aclcheck_error(aclresult, ACL_KIND_PROC,
285  NameListToString(restrictionName));
286 
287  return restrictionOid;
288 }
289 
290 /*
291  * Look up a join estimator function ny name, and verify that it has the
292  * correct signature and we have the permissions to attach it to an
293  * operator.
294  */
295 static Oid
297 {
298  Oid typeId[5];
299  Oid joinOid;
300  AclResult aclresult;
301 
302  typeId[0] = INTERNALOID; /* PlannerInfo */
303  typeId[1] = OIDOID; /* operator OID */
304  typeId[2] = INTERNALOID; /* args list */
305  typeId[3] = INT2OID; /* jointype */
306  typeId[4] = INTERNALOID; /* SpecialJoinInfo */
307 
308  /*
309  * As of Postgres 8.4, the preferred signature for join estimators has 5
310  * arguments, but we still allow the old 4-argument form. Try the
311  * preferred form first.
312  */
313  joinOid = LookupFuncName(joinName, 5, typeId, true);
314  if (!OidIsValid(joinOid))
315  joinOid = LookupFuncName(joinName, 4, typeId, true);
316  /* If not found, reference the 5-argument signature in error msg */
317  if (!OidIsValid(joinOid))
318  joinOid = LookupFuncName(joinName, 5, typeId, false);
319 
320  /* estimators must return float8 */
321  if (get_func_rettype(joinOid) != FLOAT8OID)
322  ereport(ERROR,
323  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
324  errmsg("join estimator function %s must return type %s",
325  NameListToString(joinName), "float8")));
326 
327  /* Require EXECUTE rights for the estimator */
328  aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
329  if (aclresult != ACLCHECK_OK)
330  aclcheck_error(aclresult, ACL_KIND_PROC,
331  NameListToString(joinName));
332 
333  return joinOid;
334 }
335 
336 /*
337  * Guts of operator deletion.
338  */
339 void
341 {
342  Relation relation;
343  HeapTuple tup;
344  Form_pg_operator op;
345 
347 
348  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
349  if (!HeapTupleIsValid(tup)) /* should not happen */
350  elog(ERROR, "cache lookup failed for operator %u", operOid);
351  op = (Form_pg_operator) GETSTRUCT(tup);
352 
353  /*
354  * Reset links from commutator and negator, if any. In case of a
355  * self-commutator or self-negator, this means we have to re-fetch the
356  * updated tuple. (We could optimize away updates on the tuple we're
357  * about to drop, but it doesn't seem worth convoluting the logic for.)
358  */
359  if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
360  {
361  OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
362  if (operOid == op->oprcom || operOid == op->oprnegate)
363  {
364  ReleaseSysCache(tup);
365  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
366  if (!HeapTupleIsValid(tup)) /* should not happen */
367  elog(ERROR, "cache lookup failed for operator %u", operOid);
368  }
369  }
370 
371  CatalogTupleDelete(relation, &tup->t_self);
372 
373  ReleaseSysCache(tup);
374 
375  heap_close(relation, RowExclusiveLock);
376 }
377 
378 /*
379  * AlterOperator
380  * routine implementing ALTER OPERATOR <operator> SET (option = ...).
381  *
382  * Currently, only RESTRICT and JOIN estimator functions can be changed.
383  */
386 {
387  ObjectAddress address;
388  Oid oprId;
389  Relation catalog;
390  HeapTuple tup;
391  Form_pg_operator oprForm;
392  int i;
393  ListCell *pl;
395  bool nulls[Natts_pg_operator];
396  bool replaces[Natts_pg_operator];
397  List *restrictionName = NIL; /* optional restrict. sel. procedure */
398  bool updateRestriction = false;
399  Oid restrictionOid;
400  List *joinName = NIL; /* optional join sel. procedure */
401  bool updateJoin = false;
402  Oid joinOid;
403 
404  /* Look up the operator */
405  oprId = LookupOperWithArgs(stmt->opername, false);
408  if (tup == NULL)
409  elog(ERROR, "cache lookup failed for operator %u", oprId);
410  oprForm = (Form_pg_operator) GETSTRUCT(tup);
411 
412  /* Process options */
413  foreach(pl, stmt->options)
414  {
415  DefElem *defel = (DefElem *) lfirst(pl);
416  List *param;
417 
418  if (defel->arg == NULL)
419  param = NIL; /* NONE, removes the function */
420  else
421  param = defGetQualifiedName(defel);
422 
423  if (pg_strcasecmp(defel->defname, "restrict") == 0)
424  {
425  restrictionName = param;
426  updateRestriction = true;
427  }
428  else if (pg_strcasecmp(defel->defname, "join") == 0)
429  {
430  joinName = param;
431  updateJoin = true;
432  }
433 
434  /*
435  * The rest of the options that CREATE accepts cannot be changed.
436  * Check for them so that we can give a meaningful error message.
437  */
438  else if (pg_strcasecmp(defel->defname, "leftarg") == 0 ||
439  pg_strcasecmp(defel->defname, "rightarg") == 0 ||
440  pg_strcasecmp(defel->defname, "procedure") == 0 ||
441  pg_strcasecmp(defel->defname, "commutator") == 0 ||
442  pg_strcasecmp(defel->defname, "negator") == 0 ||
443  pg_strcasecmp(defel->defname, "hashes") == 0 ||
444  pg_strcasecmp(defel->defname, "merges") == 0)
445  {
446  ereport(ERROR,
447  (errcode(ERRCODE_SYNTAX_ERROR),
448  errmsg("operator attribute \"%s\" cannot be changed",
449  defel->defname)));
450  }
451  else
452  ereport(ERROR,
453  (errcode(ERRCODE_SYNTAX_ERROR),
454  errmsg("operator attribute \"%s\" not recognized",
455  defel->defname)));
456  }
457 
458  /* Check permissions. Must be owner. */
459  if (!pg_oper_ownercheck(oprId, GetUserId()))
461  NameStr(oprForm->oprname));
462 
463  /*
464  * Look up restriction and join estimators if specified
465  */
466  if (restrictionName)
467  restrictionOid = ValidateRestrictionEstimator(restrictionName);
468  else
469  restrictionOid = InvalidOid;
470  if (joinName)
471  joinOid = ValidateJoinEstimator(joinName);
472  else
473  joinOid = InvalidOid;
474 
475  /* Perform additional checks, like OperatorCreate does */
476  if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
477  {
478  /* If it's not a binary op, these things mustn't be set: */
479  if (OidIsValid(joinOid))
480  ereport(ERROR,
481  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
482  errmsg("only binary operators can have join selectivity")));
483  }
484 
485  if (oprForm->oprresult != BOOLOID)
486  {
487  if (OidIsValid(restrictionOid))
488  ereport(ERROR,
489  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
490  errmsg("only boolean operators can have restriction selectivity")));
491  if (OidIsValid(joinOid))
492  ereport(ERROR,
493  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
494  errmsg("only boolean operators can have join selectivity")));
495  }
496 
497  /* Update the tuple */
498  for (i = 0; i < Natts_pg_operator; ++i)
499  {
500  values[i] = (Datum) 0;
501  replaces[i] = false;
502  nulls[i] = false;
503  }
504  if (updateRestriction)
505  {
506  replaces[Anum_pg_operator_oprrest - 1] = true;
507  values[Anum_pg_operator_oprrest - 1] = restrictionOid;
508  }
509  if (updateJoin)
510  {
511  replaces[Anum_pg_operator_oprjoin - 1] = true;
512  values[Anum_pg_operator_oprjoin - 1] = joinOid;
513  }
514 
515  tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
516  values, nulls, replaces);
517 
518  CatalogTupleUpdate(catalog, &tup->t_self, tup);
519 
520  address = makeOperatorDependencies(tup, true);
521 
523 
524  heap_close(catalog, NoLock);
525 
526  return address;
527 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:140
#define NIL
Definition: pg_list.h:69
ObjectAddress DefineOperator(List *names, List *parameters)
Definition: operatorcmds.c:68
#define OperatorRelationId
Definition: pg_operator.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
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:324
#define RelationGetDescr(relation)
Definition: rel.h:429
Oid GetUserId(void)
Definition: miscinit.c:283
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:764
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:296
#define OIDOID
Definition: pg_type.h:328
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2846
#define INT4OID
Definition: pg_type.h:316
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4598
int errcode(int sqlerrcode)
Definition: elog.c:575
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
#define heap_close(r, l)
Definition: heapam.h:97
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define Anum_pg_operator_oprjoin
Definition: pg_operator.h:78
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3457
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1459
void RemoveOperatorById(Oid operOid)
Definition: operatorcmds.c:340
bool defGetBoolean(DefElem *def)
Definition: define.c:111
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:255
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
ObjectAddress AlterOperator(AlterOperatorStmt *stmt)
Definition: operatorcmds.c:385
bool setof
Definition: parsenodes.h:211
ItemPointerData t_self
Definition: htup.h:65
#define INT2OID
Definition: pg_type.h:308
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3038
#define NoLock
Definition: lockdefs.h:34
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ACL_USAGE
Definition: parsenodes.h:80
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:261
Node * arg
Definition: parsenodes.h:720
#define Anum_pg_operator_oprrest
Definition: pg_operator.h:77
#define WARNING
Definition: elog.h:40
char * NameListToString(List *names)
Definition: namespace.c:2953
ObjectWithArgs * opername
Definition: parsenodes.h:2824
AclResult
Definition: acl.h:170
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
#define InvalidOid
Definition: postgres_ext.h:36
#define INTERNALOID
Definition: pg_type.h:698
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:645
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
List * defGetQualifiedName(DefElem *def)
Definition: define.c:223
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define FLOAT8OID
Definition: pg_type.h:419
#define BOOLOID
Definition: pg_type.h:288
FormData_pg_operator* Form_pg_operator
Definition: pg_operator.h:57
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
Definition: parse_func.c:1910
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:161
#define Natts_pg_operator
Definition: pg_operator.h:64
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define ACL_EXECUTE
Definition: parsenodes.h:79
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4446
int i
#define NameStr(name)
Definition: c.h:499
char * defname
Definition: parsenodes.h:719
#define elog
Definition: elog.h:219
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4534
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:793
Definition: pg_list.h:45
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274