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-2019, 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/builtins.h"
48 #include "utils/lsyscache.h"
49 #include "utils/rel.h"
50 #include "utils/syscache.h"
51 
52 static Oid ValidateRestrictionEstimator(List *restrictionName);
53 static Oid ValidateJoinEstimator(List *joinName);
54 
55 /*
56  * DefineOperator
57  * this function extracts all the information from the
58  * parameter list generated by the parser and then has
59  * OperatorCreate() do all the actual work.
60  *
61  * 'parameters' is a list of DefElem
62  */
64 DefineOperator(List *names, List *parameters)
65 {
66  char *oprName;
67  Oid oprNamespace;
68  AclResult aclresult;
69  bool canMerge = false; /* operator merges */
70  bool canHash = false; /* operator hashes */
71  List *functionName = NIL; /* function for operator */
72  TypeName *typeName1 = NULL; /* first type name */
73  TypeName *typeName2 = NULL; /* second type name */
74  Oid typeId1 = InvalidOid; /* types converted to OID */
75  Oid typeId2 = InvalidOid;
76  Oid rettype;
77  List *commutatorName = NIL; /* optional commutator operator name */
78  List *negatorName = NIL; /* optional negator operator name */
79  List *restrictionName = NIL; /* optional restrict. sel. function */
80  List *joinName = NIL; /* optional join sel. function */
81  Oid functionOid; /* functions converted to OID */
82  Oid restrictionOid;
83  Oid joinOid;
84  Oid typeId[2]; /* to hold left and right arg */
85  int nargs;
86  ListCell *pl;
87 
88  /* Convert list of names to a name and namespace */
89  oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
90 
91  /* Check we have creation rights in target namespace */
92  aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
93  if (aclresult != ACLCHECK_OK)
94  aclcheck_error(aclresult, OBJECT_SCHEMA,
95  get_namespace_name(oprNamespace));
96 
97  /*
98  * loop over the definition list and extract the information we need.
99  */
100  foreach(pl, parameters)
101  {
102  DefElem *defel = (DefElem *) lfirst(pl);
103 
104  if (strcmp(defel->defname, "leftarg") == 0)
105  {
106  typeName1 = defGetTypeName(defel);
107  if (typeName1->setof)
108  ereport(ERROR,
109  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
110  errmsg("SETOF type not allowed for operator argument")));
111  }
112  else if (strcmp(defel->defname, "rightarg") == 0)
113  {
114  typeName2 = defGetTypeName(defel);
115  if (typeName2->setof)
116  ereport(ERROR,
117  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
118  errmsg("SETOF type not allowed for operator argument")));
119  }
120  /* "function" and "procedure" are equivalent here */
121  else if (strcmp(defel->defname, "function") == 0)
122  functionName = defGetQualifiedName(defel);
123  else if (strcmp(defel->defname, "procedure") == 0)
124  functionName = defGetQualifiedName(defel);
125  else if (strcmp(defel->defname, "commutator") == 0)
126  commutatorName = defGetQualifiedName(defel);
127  else if (strcmp(defel->defname, "negator") == 0)
128  negatorName = defGetQualifiedName(defel);
129  else if (strcmp(defel->defname, "restrict") == 0)
130  restrictionName = defGetQualifiedName(defel);
131  else if (strcmp(defel->defname, "join") == 0)
132  joinName = defGetQualifiedName(defel);
133  else if (strcmp(defel->defname, "hashes") == 0)
134  canHash = defGetBoolean(defel);
135  else if (strcmp(defel->defname, "merges") == 0)
136  canMerge = defGetBoolean(defel);
137  /* These obsolete options are taken as meaning canMerge */
138  else if (strcmp(defel->defname, "sort1") == 0)
139  canMerge = true;
140  else if (strcmp(defel->defname, "sort2") == 0)
141  canMerge = true;
142  else if (strcmp(defel->defname, "ltcmp") == 0)
143  canMerge = true;
144  else if (strcmp(defel->defname, "gtcmp") == 0)
145  canMerge = true;
146  else
147  {
148  /* WARNING, not ERROR, for historical backwards-compatibility */
150  (errcode(ERRCODE_SYNTAX_ERROR),
151  errmsg("operator attribute \"%s\" not recognized",
152  defel->defname)));
153  }
154  }
155 
156  /*
157  * make sure we have our required definitions
158  */
159  if (functionName == NIL)
160  ereport(ERROR,
161  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
162  errmsg("operator function must be specified")));
163 
164  /* Transform type names to type OIDs */
165  if (typeName1)
166  typeId1 = typenameTypeId(NULL, typeName1);
167  if (typeName2)
168  typeId2 = typenameTypeId(NULL, typeName2);
169 
170  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
171  ereport(ERROR,
172  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
173  errmsg("at least one of leftarg or rightarg must be specified")));
174 
175  if (typeName1)
176  {
177  aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
178  if (aclresult != ACLCHECK_OK)
179  aclcheck_error_type(aclresult, typeId1);
180  }
181 
182  if (typeName2)
183  {
184  aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
185  if (aclresult != ACLCHECK_OK)
186  aclcheck_error_type(aclresult, typeId2);
187  }
188 
189  /*
190  * Look up the operator's underlying function.
191  */
192  if (!OidIsValid(typeId1))
193  {
194  typeId[0] = typeId2;
195  nargs = 1;
196  }
197  else if (!OidIsValid(typeId2))
198  {
199  typeId[0] = typeId1;
200  nargs = 1;
201  }
202  else
203  {
204  typeId[0] = typeId1;
205  typeId[1] = typeId2;
206  nargs = 2;
207  }
208  functionOid = LookupFuncName(functionName, nargs, typeId, false);
209 
210  /*
211  * We require EXECUTE rights for the function. This isn't strictly
212  * necessary, since EXECUTE will be checked at any attempted use of the
213  * operator, but it seems like a good idea anyway.
214  */
215  aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
216  if (aclresult != ACLCHECK_OK)
217  aclcheck_error(aclresult, OBJECT_FUNCTION,
218  NameListToString(functionName));
219 
220  rettype = get_func_rettype(functionOid);
221  aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
222  if (aclresult != ACLCHECK_OK)
223  aclcheck_error_type(aclresult, rettype);
224 
225  /*
226  * Look up restriction and join estimators if specified
227  */
228  if (restrictionName)
229  restrictionOid = ValidateRestrictionEstimator(restrictionName);
230  else
231  restrictionOid = InvalidOid;
232  if (joinName)
233  joinOid = ValidateJoinEstimator(joinName);
234  else
235  joinOid = InvalidOid;
236 
237  /*
238  * now have OperatorCreate do all the work..
239  */
240  return
241  OperatorCreate(oprName, /* operator name */
242  oprNamespace, /* namespace */
243  typeId1, /* left type id */
244  typeId2, /* right type id */
245  functionOid, /* function for operator */
246  commutatorName, /* optional commutator operator name */
247  negatorName, /* optional negator operator name */
248  restrictionOid, /* optional restrict. sel. function */
249  joinOid, /* optional join sel. function name */
250  canMerge, /* operator merges */
251  canHash); /* operator hashes */
252 }
253 
254 /*
255  * Look up a restriction estimator function ny name, and verify that it has
256  * the correct signature and we have the permissions to attach it to an
257  * operator.
258  */
259 static Oid
261 {
262  Oid typeId[4];
263  Oid restrictionOid;
264  AclResult aclresult;
265 
266  typeId[0] = INTERNALOID; /* PlannerInfo */
267  typeId[1] = OIDOID; /* operator OID */
268  typeId[2] = INTERNALOID; /* args list */
269  typeId[3] = INT4OID; /* varRelid */
270 
271  restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
272 
273  /* estimators must return float8 */
274  if (get_func_rettype(restrictionOid) != FLOAT8OID)
275  ereport(ERROR,
276  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
277  errmsg("restriction estimator function %s must return type %s",
278  NameListToString(restrictionName), "float8")));
279 
280  /* Require EXECUTE rights for the estimator */
281  aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
282  if (aclresult != ACLCHECK_OK)
283  aclcheck_error(aclresult, OBJECT_FUNCTION,
284  NameListToString(restrictionName));
285 
286  return restrictionOid;
287 }
288 
289 /*
290  * Look up a join estimator function ny name, and verify that it has the
291  * correct signature and we have the permissions to attach it to an
292  * operator.
293  */
294 static Oid
296 {
297  Oid typeId[5];
298  Oid joinOid;
299  AclResult aclresult;
300 
301  typeId[0] = INTERNALOID; /* PlannerInfo */
302  typeId[1] = OIDOID; /* operator OID */
303  typeId[2] = INTERNALOID; /* args list */
304  typeId[3] = INT2OID; /* jointype */
305  typeId[4] = INTERNALOID; /* SpecialJoinInfo */
306 
307  /*
308  * As of Postgres 8.4, the preferred signature for join estimators has 5
309  * arguments, but we still allow the old 4-argument form. Try the
310  * preferred form first.
311  */
312  joinOid = LookupFuncName(joinName, 5, typeId, true);
313  if (!OidIsValid(joinOid))
314  joinOid = LookupFuncName(joinName, 4, typeId, true);
315  /* If not found, reference the 5-argument signature in error msg */
316  if (!OidIsValid(joinOid))
317  joinOid = LookupFuncName(joinName, 5, typeId, false);
318 
319  /* estimators must return float8 */
320  if (get_func_rettype(joinOid) != FLOAT8OID)
321  ereport(ERROR,
322  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
323  errmsg("join estimator function %s must return type %s",
324  NameListToString(joinName), "float8")));
325 
326  /* Require EXECUTE rights for the estimator */
327  aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
328  if (aclresult != ACLCHECK_OK)
329  aclcheck_error(aclresult, OBJECT_FUNCTION,
330  NameListToString(joinName));
331 
332  return joinOid;
333 }
334 
335 /*
336  * Guts of operator deletion.
337  */
338 void
340 {
341  Relation relation;
342  HeapTuple tup;
343  Form_pg_operator op;
344 
345  relation = table_open(OperatorRelationId, RowExclusiveLock);
346 
347  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
348  if (!HeapTupleIsValid(tup)) /* should not happen */
349  elog(ERROR, "cache lookup failed for operator %u", operOid);
350  op = (Form_pg_operator) GETSTRUCT(tup);
351 
352  /*
353  * Reset links from commutator and negator, if any. In case of a
354  * self-commutator or self-negator, this means we have to re-fetch the
355  * updated tuple. (We could optimize away updates on the tuple we're
356  * about to drop, but it doesn't seem worth convoluting the logic for.)
357  */
358  if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
359  {
360  OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
361  if (operOid == op->oprcom || operOid == op->oprnegate)
362  {
363  ReleaseSysCache(tup);
364  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
365  if (!HeapTupleIsValid(tup)) /* should not happen */
366  elog(ERROR, "cache lookup failed for operator %u", operOid);
367  }
368  }
369 
370  CatalogTupleDelete(relation, &tup->t_self);
371 
372  ReleaseSysCache(tup);
373 
374  table_close(relation, RowExclusiveLock);
375 }
376 
377 /*
378  * AlterOperator
379  * routine implementing ALTER OPERATOR <operator> SET (option = ...).
380  *
381  * Currently, only RESTRICT and JOIN estimator functions can be changed.
382  */
385 {
386  ObjectAddress address;
387  Oid oprId;
388  Relation catalog;
389  HeapTuple tup;
390  Form_pg_operator oprForm;
391  int i;
392  ListCell *pl;
393  Datum values[Natts_pg_operator];
394  bool nulls[Natts_pg_operator];
395  bool replaces[Natts_pg_operator];
396  List *restrictionName = NIL; /* optional restrict. sel. function */
397  bool updateRestriction = false;
398  Oid restrictionOid;
399  List *joinName = NIL; /* optional join sel. function */
400  bool updateJoin = false;
401  Oid joinOid;
402 
403  /* Look up the operator */
404  oprId = LookupOperWithArgs(stmt->opername, false);
405  catalog = table_open(OperatorRelationId, RowExclusiveLock);
407  if (!HeapTupleIsValid(tup))
408  elog(ERROR, "cache lookup failed for operator %u", oprId);
409  oprForm = (Form_pg_operator) GETSTRUCT(tup);
410 
411  /* Process options */
412  foreach(pl, stmt->options)
413  {
414  DefElem *defel = (DefElem *) lfirst(pl);
415  List *param;
416 
417  if (defel->arg == NULL)
418  param = NIL; /* NONE, removes the function */
419  else
420  param = defGetQualifiedName(defel);
421 
422  if (strcmp(defel->defname, "restrict") == 0)
423  {
424  restrictionName = param;
425  updateRestriction = true;
426  }
427  else if (strcmp(defel->defname, "join") == 0)
428  {
429  joinName = param;
430  updateJoin = true;
431  }
432 
433  /*
434  * The rest of the options that CREATE accepts cannot be changed.
435  * Check for them so that we can give a meaningful error message.
436  */
437  else if (strcmp(defel->defname, "leftarg") == 0 ||
438  strcmp(defel->defname, "rightarg") == 0 ||
439  strcmp(defel->defname, "function") == 0 ||
440  strcmp(defel->defname, "procedure") == 0 ||
441  strcmp(defel->defname, "commutator") == 0 ||
442  strcmp(defel->defname, "negator") == 0 ||
443  strcmp(defel->defname, "hashes") == 0 ||
444  strcmp(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 
522  InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
523 
524  table_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:65
ObjectAddress DefineOperator(List *names, List *parameters)
Definition: operatorcmds.c:64
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#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:448
Oid GetUserId(void)
Definition: miscinit.c:380
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:773
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:295
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2987
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4805
int errcode(int sqlerrcode)
Definition: elog.c:608
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4691
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3665
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1457
void RemoveOperatorById(Oid operOid)
Definition: operatorcmds.c:339
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
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:384
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2101
bool setof
Definition: parsenodes.h:211
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ACL_USAGE
Definition: parsenodes.h:82
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:260
Node * arg
Definition: parsenodes.h:731
#define WARNING
Definition: elog.h:40
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3094
ObjectWithArgs * opername
Definition: parsenodes.h:2950
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 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:224
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:174
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define ACL_EXECUTE
Definition: parsenodes.h:81
#define elog(elevel,...)
Definition: elog.h:228
AclResult pg_proc_aclcheck(Oid proc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4653
int i
#define NameStr(name)
Definition: c.h:616
char * defname
Definition: parsenodes.h:730
AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4741
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