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