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-2025, 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"
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
41static Oid OperatorGet(const char *operatorName,
42 Oid operatorNamespace,
43 Oid leftObjectId,
44 Oid rightObjectId,
45 bool *defined);
46
47static Oid OperatorShellMake(const char *operatorName,
48 Oid operatorNamespace,
49 Oid leftTypeId,
50 Oid rightTypeId);
51
52static 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 */
67static bool
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 */
123static Oid
124OperatorGet(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 */
163Oid
164OperatorLookup(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 */
192static Oid
193OperatorShellMake(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))
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 */
321OperatorCreate(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))
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)
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)
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 */
555void
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)
571 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572 errmsg("only binary operators can have commutators")));
573 if (hasJoinSelectivity)
575 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
576 errmsg("only binary operators can have join selectivity")));
577 if (canMerge)
579 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
580 errmsg("only binary operators can merge join")));
581 if (canHash)
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)
592 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593 errmsg("only boolean operators can have negators")));
594 if (hasRestrictionSelectivity)
596 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
597 errmsg("only boolean operators can have restriction selectivity")));
598 if (hasJoinSelectivity)
600 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601 errmsg("only boolean operators can have join selectivity")));
602 if (canMerge)
604 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
605 errmsg("only boolean operators can merge join")));
606 if (canHash)
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 */
621static Oid
622get_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 */
683void
684OperatorUpd(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)
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
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)
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
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
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:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define NameStr(name)
Definition: c.h:703
#define RegProcedureIsValid(p)
Definition: c.h:734
regproc RegProcedure
Definition: c.h:607
#define OidIsValid(objectId)
Definition: c.h:732
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#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
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
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:72
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_opname(Oid opno)
Definition: lsyscache.c:1310
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
Oid GetUserId(void)
Definition: miscinit.c:517
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char * NameListToString(const List *names)
Definition: namespace.c:3594
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
#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:2348
@ OBJECT_OPERATOR
Definition: parsenodes.h:2337
#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:301
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
#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:1047
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:698
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:254
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
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:1099