PostgreSQL Source Code  git master
pg_operator.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_operator.c
4  * routines to support manipulation of the pg_operator relation
5  *
6  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/catalog/pg_operator.c
12  *
13  * NOTES
14  * these routines moved here from commands/define.c and somewhat cleaned up.
15  *
16  *-------------------------------------------------------------------------
17  */
18 #include "postgres.h"
19 
20 #include "access/htup_details.h"
21 #include "access/table.h"
22 #include "access/xact.h"
23 #include "catalog/catalog.h"
24 #include "catalog/dependency.h"
25 #include "catalog/indexing.h"
26 #include "catalog/namespace.h"
27 #include "catalog/objectaccess.h"
28 #include "catalog/pg_namespace.h"
29 #include "catalog/pg_operator.h"
30 #include "catalog/pg_proc.h"
31 #include "catalog/pg_type.h"
32 #include "miscadmin.h"
33 #include "parser/parse_oper.h"
34 #include "utils/acl.h"
35 #include "utils/builtins.h"
36 #include "utils/lsyscache.h"
37 #include "utils/rel.h"
38 #include "utils/syscache.h"
39 
40 
41 static Oid OperatorGet(const char *operatorName,
42  Oid operatorNamespace,
43  Oid leftObjectId,
44  Oid rightObjectId,
45  bool *defined);
46 
47 static Oid OperatorLookup(List *operatorName,
48  Oid leftObjectId,
49  Oid rightObjectId,
50  bool *defined);
51 
52 static Oid OperatorShellMake(const char *operatorName,
53  Oid operatorNamespace,
54  Oid leftTypeId,
55  Oid rightTypeId);
56 
57 static Oid get_other_operator(List *otherOp,
58  Oid otherLeftTypeId, Oid otherRightTypeId,
59  const char *operatorName, Oid operatorNamespace,
60  Oid leftTypeId, Oid rightTypeId,
61  bool isCommutator);
62 
63 
64 /*
65  * Check whether a proposed operator name is legal
66  *
67  * This had better match the behavior of parser/scan.l!
68  *
69  * We need this because the parser is not smart enough to check that
70  * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
71  * are operator names rather than some other lexical entity.
72  */
73 static bool
74 validOperatorName(const char *name)
75 {
76  size_t len = strlen(name);
77 
78  /* Can't be empty or too long */
79  if (len == 0 || len >= NAMEDATALEN)
80  return false;
81 
82  /* Can't contain any invalid characters */
83  /* Test string here should match op_chars in scan.l */
84  if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
85  return false;
86 
87  /* Can't contain slash-star or dash-dash (comment starts) */
88  if (strstr(name, "/*") || strstr(name, "--"))
89  return false;
90 
91  /*
92  * For SQL standard compatibility, '+' and '-' cannot be the last char of
93  * a multi-char operator unless the operator contains chars that are not
94  * in SQL operators. The idea is to lex '=-' as two operators, but not to
95  * forbid operator names like '?-' that could not be sequences of standard
96  * SQL operators.
97  */
98  if (len > 1 &&
99  (name[len - 1] == '+' ||
100  name[len - 1] == '-'))
101  {
102  int ic;
103 
104  for (ic = len - 2; ic >= 0; ic--)
105  {
106  if (strchr("~!@#^&|`?%", name[ic]))
107  break;
108  }
109  if (ic < 0)
110  return false; /* nope, not valid */
111  }
112 
113  /* != isn't valid either, because parser will convert it to <> */
114  if (strcmp(name, "!=") == 0)
115  return false;
116 
117  return true;
118 }
119 
120 
121 /*
122  * OperatorGet
123  *
124  * finds an operator given an exact specification (name, namespace,
125  * left and right type IDs).
126  *
127  * *defined is set true if defined (not a shell)
128  */
129 static Oid
130 OperatorGet(const char *operatorName,
131  Oid operatorNamespace,
132  Oid leftObjectId,
133  Oid rightObjectId,
134  bool *defined)
135 {
136  HeapTuple tup;
137  Oid operatorObjectId;
138 
140  PointerGetDatum(operatorName),
141  ObjectIdGetDatum(leftObjectId),
142  ObjectIdGetDatum(rightObjectId),
143  ObjectIdGetDatum(operatorNamespace));
144  if (HeapTupleIsValid(tup))
145  {
147 
148  operatorObjectId = oprform->oid;
149  *defined = RegProcedureIsValid(oprform->oprcode);
150  ReleaseSysCache(tup);
151  }
152  else
153  {
154  operatorObjectId = InvalidOid;
155  *defined = false;
156  }
157 
158  return operatorObjectId;
159 }
160 
161 /*
162  * OperatorLookup
163  *
164  * looks up an operator given a possibly-qualified name and
165  * left and right type IDs.
166  *
167  * *defined is set true if defined (not a shell)
168  */
169 static Oid
170 OperatorLookup(List *operatorName,
171  Oid leftObjectId,
172  Oid rightObjectId,
173  bool *defined)
174 {
175  Oid operatorObjectId;
176  RegProcedure oprcode;
177 
178  operatorObjectId = LookupOperName(NULL, operatorName,
179  leftObjectId, rightObjectId,
180  true, -1);
181  if (!OidIsValid(operatorObjectId))
182  {
183  *defined = false;
184  return InvalidOid;
185  }
186 
187  oprcode = get_opcode(operatorObjectId);
188  *defined = RegProcedureIsValid(oprcode);
189 
190  return operatorObjectId;
191 }
192 
193 
194 /*
195  * OperatorShellMake
196  * Make a "shell" entry for a not-yet-existing operator.
197  */
198 static Oid
199 OperatorShellMake(const char *operatorName,
200  Oid operatorNamespace,
201  Oid leftTypeId,
202  Oid rightTypeId)
203 {
204  Relation pg_operator_desc;
205  Oid operatorObjectId;
206  int i;
207  HeapTuple tup;
208  Datum values[Natts_pg_operator];
209  bool nulls[Natts_pg_operator];
210  NameData oname;
211  TupleDesc tupDesc;
212 
213  /*
214  * validate operator name
215  */
216  if (!validOperatorName(operatorName))
217  ereport(ERROR,
218  (errcode(ERRCODE_INVALID_NAME),
219  errmsg("\"%s\" is not a valid operator name",
220  operatorName)));
221 
222  /*
223  * open pg_operator
224  */
225  pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
226  tupDesc = pg_operator_desc->rd_att;
227 
228  /*
229  * initialize our *nulls and *values arrays
230  */
231  for (i = 0; i < Natts_pg_operator; ++i)
232  {
233  nulls[i] = false;
234  values[i] = (Datum) NULL; /* redundant, but safe */
235  }
236 
237  /*
238  * initialize values[] with the operator name and input data types. Note
239  * that oprcode is set to InvalidOid, indicating it's a shell.
240  */
241  operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId,
242  Anum_pg_operator_oid);
243  values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
244  namestrcpy(&oname, operatorName);
245  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
246  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
247  values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
248  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
249  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
250  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
251  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
252  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
253  values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
254  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
255  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
256  values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
257  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
258  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
259 
260  /*
261  * create a new operator tuple
262  */
263  tup = heap_form_tuple(tupDesc, values, nulls);
264 
265  /*
266  * insert our "shell" operator tuple
267  */
268  CatalogTupleInsert(pg_operator_desc, tup);
269 
270  /* Add dependencies for the entry */
271  makeOperatorDependencies(tup, true, false);
272 
273  heap_freetuple(tup);
274 
275  /* Post creation hook for new shell operator */
276  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
277 
278  /*
279  * Make sure the tuple is visible for subsequent lookups/updates.
280  */
282 
283  /*
284  * close the operator relation and return the oid.
285  */
286  table_close(pg_operator_desc, RowExclusiveLock);
287 
288  return operatorObjectId;
289 }
290 
291 /*
292  * OperatorCreate
293  *
294  * "X" indicates an optional argument (i.e. one that can be NULL or 0)
295  * operatorName name for new operator
296  * operatorNamespace namespace for new operator
297  * leftTypeId X left type ID
298  * rightTypeId X right type ID
299  * procedureId procedure ID for operator
300  * commutatorName X commutator operator
301  * negatorName X negator operator
302  * restrictionId X restriction selectivity procedure ID
303  * joinId X join selectivity procedure ID
304  * canMerge merge join can be used with this operator
305  * canHash hash join can be used with this operator
306  *
307  * The caller should have validated properties and permissions for the
308  * objects passed as OID references. We must handle the commutator and
309  * negator operator references specially, however, since those need not
310  * exist beforehand.
311  *
312  * This routine gets complicated because it allows the user to
313  * specify operators that do not exist. For example, if operator
314  * "op" is being defined, the negator operator "negop" and the
315  * commutator "commop" can also be defined without specifying
316  * any information other than their names. Since in order to
317  * add "op" to the PG_OPERATOR catalog, all the Oid's for these
318  * operators must be placed in the fields of "op", a forward
319  * declaration is done on the commutator and negator operators.
320  * This is called creating a shell, and its main effect is to
321  * create a tuple in the PG_OPERATOR catalog with minimal
322  * information about the operator (just its name and types).
323  * Forward declaration is used only for this purpose, it is
324  * not available to the user as it is for type definition.
325  */
327 OperatorCreate(const char *operatorName,
328  Oid operatorNamespace,
329  Oid leftTypeId,
330  Oid rightTypeId,
331  Oid procedureId,
332  List *commutatorName,
333  List *negatorName,
334  Oid restrictionId,
335  Oid joinId,
336  bool canMerge,
337  bool canHash)
338 {
339  Relation pg_operator_desc;
340  HeapTuple tup;
341  bool isUpdate;
342  bool nulls[Natts_pg_operator];
343  bool replaces[Natts_pg_operator];
344  Datum values[Natts_pg_operator];
345  Oid operatorObjectId;
346  bool operatorAlreadyDefined;
347  Oid operResultType;
348  Oid commutatorId,
349  negatorId;
350  bool selfCommutator = false;
351  NameData oname;
352  int i;
353  ObjectAddress address;
354 
355  /*
356  * Sanity checks
357  */
358  if (!validOperatorName(operatorName))
359  ereport(ERROR,
360  (errcode(ERRCODE_INVALID_NAME),
361  errmsg("\"%s\" is not a valid operator name",
362  operatorName)));
363 
364  if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
365  {
366  /* If it's not a binary op, these things mustn't be set: */
367  if (commutatorName)
368  ereport(ERROR,
369  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
370  errmsg("only binary operators can have commutators")));
371  if (OidIsValid(joinId))
372  ereport(ERROR,
373  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
374  errmsg("only binary operators can have join selectivity")));
375  if (canMerge)
376  ereport(ERROR,
377  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
378  errmsg("only binary operators can merge join")));
379  if (canHash)
380  ereport(ERROR,
381  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
382  errmsg("only binary operators can hash")));
383  }
384 
385  operResultType = get_func_rettype(procedureId);
386 
387  if (operResultType != BOOLOID)
388  {
389  /* If it's not a boolean op, these things mustn't be set: */
390  if (negatorName)
391  ereport(ERROR,
392  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393  errmsg("only boolean operators can have negators")));
394  if (OidIsValid(restrictionId))
395  ereport(ERROR,
396  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
397  errmsg("only boolean operators can have restriction selectivity")));
398  if (OidIsValid(joinId))
399  ereport(ERROR,
400  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
401  errmsg("only boolean operators can have join selectivity")));
402  if (canMerge)
403  ereport(ERROR,
404  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
405  errmsg("only boolean operators can merge join")));
406  if (canHash)
407  ereport(ERROR,
408  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
409  errmsg("only boolean operators can hash")));
410  }
411 
412  operatorObjectId = OperatorGet(operatorName,
413  operatorNamespace,
414  leftTypeId,
415  rightTypeId,
416  &operatorAlreadyDefined);
417 
418  if (operatorAlreadyDefined)
419  ereport(ERROR,
420  (errcode(ERRCODE_DUPLICATE_FUNCTION),
421  errmsg("operator %s already exists",
422  operatorName)));
423 
424  /*
425  * At this point, if operatorObjectId is not InvalidOid then we are
426  * filling in a previously-created shell. Insist that the user own any
427  * such shell.
428  */
429  if (OidIsValid(operatorObjectId) &&
430  !object_ownercheck(OperatorRelationId, operatorObjectId, GetUserId()))
432  operatorName);
433 
434  /*
435  * Set up the other operators. If they do not currently exist, create
436  * shells in order to get ObjectId's.
437  */
438 
439  if (commutatorName)
440  {
441  /* commutator has reversed arg types */
442  commutatorId = get_other_operator(commutatorName,
443  rightTypeId, leftTypeId,
444  operatorName, operatorNamespace,
445  leftTypeId, rightTypeId,
446  true);
447 
448  /* Permission check: must own other operator */
449  if (OidIsValid(commutatorId) &&
450  !object_ownercheck(OperatorRelationId, commutatorId, GetUserId()))
452  NameListToString(commutatorName));
453 
454  /*
455  * self-linkage to this operator; will fix below. Note that only
456  * self-linkage for commutation makes sense.
457  */
458  if (!OidIsValid(commutatorId))
459  selfCommutator = true;
460  }
461  else
462  commutatorId = InvalidOid;
463 
464  if (negatorName)
465  {
466  /* negator has same arg types */
467  negatorId = get_other_operator(negatorName,
468  leftTypeId, rightTypeId,
469  operatorName, operatorNamespace,
470  leftTypeId, rightTypeId,
471  false);
472 
473  /* Permission check: must own other operator */
474  if (OidIsValid(negatorId) &&
475  !object_ownercheck(OperatorRelationId, negatorId, GetUserId()))
477  NameListToString(negatorName));
478  }
479  else
480  negatorId = InvalidOid;
481 
482  /*
483  * set up values in the operator tuple
484  */
485 
486  for (i = 0; i < Natts_pg_operator; ++i)
487  {
488  values[i] = (Datum) NULL;
489  replaces[i] = true;
490  nulls[i] = false;
491  }
492 
493  namestrcpy(&oname, operatorName);
494  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
495  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
496  values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
497  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
498  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
499  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
500  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
501  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
502  values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
503  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
504  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
505  values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
506  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
507  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
508 
509  pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
510 
511  /*
512  * If we are replacing an operator shell, update; else insert
513  */
514  if (operatorObjectId)
515  {
516  isUpdate = true;
517 
519  ObjectIdGetDatum(operatorObjectId));
520  if (!HeapTupleIsValid(tup))
521  elog(ERROR, "cache lookup failed for operator %u",
522  operatorObjectId);
523 
524  replaces[Anum_pg_operator_oid - 1] = false;
525  tup = heap_modify_tuple(tup,
526  RelationGetDescr(pg_operator_desc),
527  values,
528  nulls,
529  replaces);
530 
531  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
532  }
533  else
534  {
535  isUpdate = false;
536 
537  operatorObjectId = GetNewOidWithIndex(pg_operator_desc,
538  OperatorOidIndexId,
539  Anum_pg_operator_oid);
540  values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
541 
542  tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
543  values, nulls);
544 
545  CatalogTupleInsert(pg_operator_desc, tup);
546  }
547 
548  /* Add dependencies for the entry */
549  address = makeOperatorDependencies(tup, true, isUpdate);
550 
551  /* Post creation hook for new operator */
552  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
553 
554  table_close(pg_operator_desc, RowExclusiveLock);
555 
556  /*
557  * If a commutator and/or negator link is provided, update the other
558  * operator(s) to point at this one, if they don't already have a link.
559  * This supports an alternative style of operator definition wherein the
560  * user first defines one operator without giving negator or commutator,
561  * then defines the other operator of the pair with the proper commutator
562  * or negator attribute. That style doesn't require creation of a shell,
563  * and it's the only style that worked right before Postgres version 6.5.
564  * This code also takes care of the situation where the new operator is
565  * its own commutator.
566  */
567  if (selfCommutator)
568  commutatorId = operatorObjectId;
569 
570  if (OidIsValid(commutatorId) || OidIsValid(negatorId))
571  OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
572 
573  return address;
574 }
575 
576 /*
577  * Try to lookup another operator (commutator, etc)
578  *
579  * If not found, check to see if it is exactly the operator we are trying
580  * to define; if so, return InvalidOid. (Note that this case is only
581  * sensible for a commutator, so we error out otherwise.) If it is not
582  * the same operator, create a shell operator.
583  */
584 static Oid
585 get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
586  const char *operatorName, Oid operatorNamespace,
587  Oid leftTypeId, Oid rightTypeId, bool isCommutator)
588 {
589  Oid other_oid;
590  bool otherDefined;
591  char *otherName;
592  Oid otherNamespace;
593  AclResult aclresult;
594 
595  other_oid = OperatorLookup(otherOp,
596  otherLeftTypeId,
597  otherRightTypeId,
598  &otherDefined);
599 
600  if (OidIsValid(other_oid))
601  {
602  /* other op already in catalogs */
603  return other_oid;
604  }
605 
606  otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
607  &otherName);
608 
609  if (strcmp(otherName, operatorName) == 0 &&
610  otherNamespace == operatorNamespace &&
611  otherLeftTypeId == leftTypeId &&
612  otherRightTypeId == rightTypeId)
613  {
614  /*
615  * self-linkage to this operator; caller will fix later. Note that
616  * only self-linkage for commutation makes sense.
617  */
618  if (!isCommutator)
619  ereport(ERROR,
620  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
621  errmsg("operator cannot be its own negator or sort operator")));
622  return InvalidOid;
623  }
624 
625  /* not in catalogs, different from operator, so make shell */
626 
627  aclresult = object_aclcheck(NamespaceRelationId, otherNamespace, GetUserId(),
628  ACL_CREATE);
629  if (aclresult != ACLCHECK_OK)
630  aclcheck_error(aclresult, OBJECT_SCHEMA,
631  get_namespace_name(otherNamespace));
632 
633  other_oid = OperatorShellMake(otherName,
634  otherNamespace,
635  otherLeftTypeId,
636  otherRightTypeId);
637  return other_oid;
638 }
639 
640 /*
641  * OperatorUpd
642  *
643  * For a given operator, look up its negator and commutator operators.
644  * When isDelete is false, update their negator and commutator fields to
645  * point back to the given operator; when isDelete is true, update those
646  * fields to no longer point back to the given operator.
647  *
648  * The !isDelete case solves a problem for users who need to insert two new
649  * operators that are the negator or commutator of each other, while the
650  * isDelete case is needed so as not to leave dangling OID links behind
651  * after dropping an operator.
652  */
653 void
654 OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
655 {
656  Relation pg_operator_desc;
657  HeapTuple tup;
658 
659  /*
660  * If we're making an operator into its own commutator, then we need a
661  * command-counter increment here, since we've just inserted the tuple
662  * we're about to update. But when we're dropping an operator, we can
663  * skip this because we're at the beginning of the command.
664  */
665  if (!isDelete)
667 
668  /* Open the relation. */
669  pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
670 
671  /* Get a writable copy of the commutator's tuple. */
672  if (OidIsValid(commId))
674  else
675  tup = NULL;
676 
677  /* Update the commutator's tuple if need be. */
678  if (HeapTupleIsValid(tup))
679  {
681  bool update_commutator = false;
682 
683  /*
684  * Out of due caution, we only change the commutator's oprcom field if
685  * it has the exact value we expected: InvalidOid when creating an
686  * operator, or baseId when dropping one.
687  */
688  if (isDelete && t->oprcom == baseId)
689  {
690  t->oprcom = InvalidOid;
691  update_commutator = true;
692  }
693  else if (!isDelete && !OidIsValid(t->oprcom))
694  {
695  t->oprcom = baseId;
696  update_commutator = true;
697  }
698 
699  /* If any columns were found to need modification, update tuple. */
700  if (update_commutator)
701  {
702  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
703 
704  /*
705  * Do CCI to make the updated tuple visible. We must do this in
706  * case the commutator is also the negator. (Which would be a
707  * logic error on the operator definer's part, but that's not a
708  * good reason to fail here.) We would need a CCI anyway in the
709  * deletion case for a self-commutator with no negator.
710  */
712  }
713  }
714 
715  /*
716  * Similarly find and update the negator, if any.
717  */
718  if (OidIsValid(negId))
720  else
721  tup = NULL;
722 
723  if (HeapTupleIsValid(tup))
724  {
726  bool update_negator = false;
727 
728  /*
729  * Out of due caution, we only change the negator's oprnegate field if
730  * it has the exact value we expected: InvalidOid when creating an
731  * operator, or baseId when dropping one.
732  */
733  if (isDelete && t->oprnegate == baseId)
734  {
735  t->oprnegate = InvalidOid;
736  update_negator = true;
737  }
738  else if (!isDelete && !OidIsValid(t->oprnegate))
739  {
740  t->oprnegate = baseId;
741  update_negator = true;
742  }
743 
744  /* If any columns were found to need modification, update tuple. */
745  if (update_negator)
746  {
747  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
748 
749  /*
750  * In the deletion case, do CCI to make the updated tuple visible.
751  * We must do this in case the operator is its own negator. (Which
752  * would be a logic error on the operator definer's part, but
753  * that's not a good reason to fail here.)
754  */
755  if (isDelete)
757  }
758  }
759 
760  /* Close relation and release catalog lock. */
761  table_close(pg_operator_desc, RowExclusiveLock);
762 }
763 
764 /*
765  * Create dependencies for an operator (either a freshly inserted
766  * complete operator, a new shell operator, a just-updated shell,
767  * or an operator that's being modified by ALTER OPERATOR).
768  *
769  * makeExtensionDep should be true when making a new operator or
770  * replacing a shell, false for ALTER OPERATOR. Passing false
771  * will prevent any change in the operator's extension membership.
772  *
773  * NB: the OidIsValid tests in this routine are necessary, in case
774  * the given operator is a shell.
775  */
778  bool makeExtensionDep,
779  bool isUpdate)
780 {
782  ObjectAddress myself,
783  referenced;
784  ObjectAddresses *addrs;
785 
786  ObjectAddressSet(myself, OperatorRelationId, oper->oid);
787 
788  /*
789  * If we are updating the operator, delete any existing entries, except
790  * for extension membership which should remain the same.
791  */
792  if (isUpdate)
793  {
794  deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
796  }
797 
798  addrs = new_object_addresses();
799 
800  /* Dependency on namespace */
801  if (OidIsValid(oper->oprnamespace))
802  {
803  ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace);
804  add_exact_object_address(&referenced, addrs);
805  }
806 
807  /* Dependency on left type */
808  if (OidIsValid(oper->oprleft))
809  {
810  ObjectAddressSet(referenced, TypeRelationId, oper->oprleft);
811  add_exact_object_address(&referenced, addrs);
812  }
813 
814  /* Dependency on right type */
815  if (OidIsValid(oper->oprright))
816  {
817  ObjectAddressSet(referenced, TypeRelationId, oper->oprright);
818  add_exact_object_address(&referenced, addrs);
819  }
820 
821  /* Dependency on result type */
822  if (OidIsValid(oper->oprresult))
823  {
824  ObjectAddressSet(referenced, TypeRelationId, oper->oprresult);
825  add_exact_object_address(&referenced, addrs);
826  }
827 
828  /*
829  * NOTE: we do not consider the operator to depend on the associated
830  * operators oprcom and oprnegate. We do not want to delete this operator
831  * if those go away, but only reset the link fields; which is not a
832  * function that the dependency logic can handle. (It's taken care of
833  * manually within RemoveOperatorById, instead.)
834  */
835 
836  /* Dependency on implementation function */
837  if (OidIsValid(oper->oprcode))
838  {
839  ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode);
840  add_exact_object_address(&referenced, addrs);
841  }
842 
843  /* Dependency on restriction selectivity function */
844  if (OidIsValid(oper->oprrest))
845  {
846  ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest);
847  add_exact_object_address(&referenced, addrs);
848  }
849 
850  /* Dependency on join selectivity function */
851  if (OidIsValid(oper->oprjoin))
852  {
853  ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin);
854  add_exact_object_address(&referenced, addrs);
855  }
856 
858  free_object_addresses(addrs);
859 
860  /* Dependency on owner */
861  recordDependencyOnOwner(OperatorRelationId, oper->oid,
862  oper->oprowner);
863 
864  /* Dependency on extension */
865  if (makeExtensionDep)
866  recordDependencyOnCurrentExtension(&myself, isUpdate);
867 
868  return myself;
869 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2669
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3760
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:3961
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define RegProcedureIsValid(p)
Definition: c.h:766
regproc RegProcedure
Definition: c.h:639
#define OidIsValid(objectId)
Definition: c.h:764
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2790
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2532
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1108
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1201
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1426
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:73
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3348
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1289
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1659
Oid GetUserId(void)
Definition: miscinit.c:509
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3020
char * NameListToString(const List *names)
Definition: namespace.c:3127
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:101
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:382
@ OBJECT_SCHEMA
Definition: parsenodes.h:2156
@ OBJECT_OPERATOR
Definition: parsenodes.h:2145
#define ACL_CREATE
Definition: parsenodes.h:92
#define NAMEDATALEN
const void size_t len
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:300
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
static Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:170
static Oid OperatorShellMake(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
Definition: pg_operator.c:199
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:130
static bool validOperatorName(const char *name)
Definition: pg_operator.c:74
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
static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, bool isCommutator)
Definition: pg_operator.c:585
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
Definition: pg_operator.c:777
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:654
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1002
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:530
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:730
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:868
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:853
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:182
@ OPERNAMENSP
Definition: syscache.h:71
@ OPEROID
Definition: syscache.h:72
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1078