Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_operator.c
4 : * routines to support manipulation of the pg_operator relation
5 : *
6 : * Portions Copyright (c) 1996-2017, 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/heapam.h"
21 : #include "access/htup_details.h"
22 : #include "access/xact.h"
23 : #include "catalog/dependency.h"
24 : #include "catalog/indexing.h"
25 : #include "catalog/namespace.h"
26 : #include "catalog/objectaccess.h"
27 : #include "catalog/pg_namespace.h"
28 : #include "catalog/pg_operator.h"
29 : #include "catalog/pg_operator_fn.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 32 : validOperatorName(const char *name)
75 : {
76 32 : size_t len = strlen(name);
77 :
78 : /* Can't be empty or too long */
79 32 : if (len == 0 || len >= NAMEDATALEN)
80 0 : return false;
81 :
82 : /* Can't contain any invalid characters */
83 : /* Test string here should match op_chars in scan.l */
84 32 : if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
85 0 : return false;
86 :
87 : /* Can't contain slash-star or dash-dash (comment starts) */
88 32 : if (strstr(name, "/*") || strstr(name, "--"))
89 0 : 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 56 : if (len > 1 &&
99 48 : (name[len - 1] == '+' ||
100 24 : name[len - 1] == '-'))
101 : {
102 : int ic;
103 :
104 0 : for (ic = len - 2; ic >= 0; ic--)
105 : {
106 0 : if (strchr("~!@#^&|`?%", name[ic]))
107 0 : break;
108 : }
109 0 : if (ic < 0)
110 0 : return false; /* nope, not valid */
111 : }
112 :
113 : /* != isn't valid either, because parser will convert it to <> */
114 32 : if (strcmp(name, "!=") == 0)
115 0 : return false;
116 :
117 32 : 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 28 : OperatorGet(const char *operatorName,
131 : Oid operatorNamespace,
132 : Oid leftObjectId,
133 : Oid rightObjectId,
134 : bool *defined)
135 : {
136 : HeapTuple tup;
137 : Oid operatorObjectId;
138 :
139 28 : tup = SearchSysCache4(OPERNAMENSP,
140 : PointerGetDatum(operatorName),
141 : ObjectIdGetDatum(leftObjectId),
142 : ObjectIdGetDatum(rightObjectId),
143 : ObjectIdGetDatum(operatorNamespace));
144 28 : if (HeapTupleIsValid(tup))
145 : {
146 0 : RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
147 :
148 0 : operatorObjectId = HeapTupleGetOid(tup);
149 0 : *defined = RegProcedureIsValid(oprcode);
150 0 : ReleaseSysCache(tup);
151 : }
152 : else
153 : {
154 28 : operatorObjectId = InvalidOid;
155 28 : *defined = false;
156 : }
157 :
158 28 : 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 14 : OperatorLookup(List *operatorName,
171 : Oid leftObjectId,
172 : Oid rightObjectId,
173 : bool *defined)
174 : {
175 : Oid operatorObjectId;
176 : RegProcedure oprcode;
177 :
178 14 : operatorObjectId = LookupOperName(NULL, operatorName,
179 : leftObjectId, rightObjectId,
180 : true, -1);
181 14 : if (!OidIsValid(operatorObjectId))
182 : {
183 11 : *defined = false;
184 11 : return InvalidOid;
185 : }
186 :
187 3 : oprcode = get_opcode(operatorObjectId);
188 3 : *defined = RegProcedureIsValid(oprcode);
189 :
190 3 : return operatorObjectId;
191 : }
192 :
193 :
194 : /*
195 : * OperatorShellMake
196 : * Make a "shell" entry for a not-yet-existing operator.
197 : */
198 : static Oid
199 4 : 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 4 : if (!validOperatorName(operatorName))
217 0 : ereport(ERROR,
218 : (errcode(ERRCODE_INVALID_NAME),
219 : errmsg("\"%s\" is not a valid operator name",
220 : operatorName)));
221 :
222 : /*
223 : * initialize our *nulls and *values arrays
224 : */
225 60 : for (i = 0; i < Natts_pg_operator; ++i)
226 : {
227 56 : nulls[i] = false;
228 56 : 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 4 : namestrcpy(&oname, operatorName);
236 4 : values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
237 4 : values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
238 4 : values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
239 4 : values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
240 4 : values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
241 4 : values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
242 4 : values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
243 4 : values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
244 4 : values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
245 4 : values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
246 4 : values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
247 4 : values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
248 4 : values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
249 4 : values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
250 :
251 : /*
252 : * open pg_operator
253 : */
254 4 : pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
255 4 : tupDesc = pg_operator_desc->rd_att;
256 :
257 : /*
258 : * create a new operator tuple
259 : */
260 4 : tup = heap_form_tuple(tupDesc, values, nulls);
261 :
262 : /*
263 : * insert our "shell" operator tuple
264 : */
265 4 : operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
266 :
267 : /* Add dependencies for the entry */
268 4 : makeOperatorDependencies(tup, false);
269 :
270 4 : heap_freetuple(tup);
271 :
272 : /* Post creation hook for new shell operator */
273 4 : InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
274 :
275 : /*
276 : * Make sure the tuple is visible for subsequent lookups/updates.
277 : */
278 4 : CommandCounterIncrement();
279 :
280 : /*
281 : * close the operator relation and return the oid.
282 : */
283 4 : heap_close(pg_operator_desc, RowExclusiveLock);
284 :
285 4 : return operatorObjectId;
286 : }
287 :
288 : /*
289 : * OperatorCreate
290 : *
291 : * "X" indicates an optional argument (i.e. one that can be NULL or 0)
292 : * operatorName name for new operator
293 : * operatorNamespace namespace for new operator
294 : * leftTypeId X left type ID
295 : * rightTypeId X right type ID
296 : * procedureId procedure ID for operator
297 : * commutatorName X commutator operator
298 : * negatorName X negator operator
299 : * restrictionId X restriction selectivity procedure ID
300 : * joinId X join selectivity procedure ID
301 : * canMerge merge join can be used with this operator
302 : * canHash hash join can be used with this operator
303 : *
304 : * The caller should have validated properties and permissions for the
305 : * objects passed as OID references. We must handle the commutator and
306 : * negator operator references specially, however, since those need not
307 : * exist beforehand.
308 : *
309 : * This routine gets complicated because it allows the user to
310 : * specify operators that do not exist. For example, if operator
311 : * "op" is being defined, the negator operator "negop" and the
312 : * commutator "commop" can also be defined without specifying
313 : * any information other than their names. Since in order to
314 : * add "op" to the PG_OPERATOR catalog, all the Oid's for these
315 : * operators must be placed in the fields of "op", a forward
316 : * declaration is done on the commutator and negator operators.
317 : * This is called creating a shell, and its main effect is to
318 : * create a tuple in the PG_OPERATOR catalog with minimal
319 : * information about the operator (just its name and types).
320 : * Forward declaration is used only for this purpose, it is
321 : * not available to the user as it is for type definition.
322 : */
323 : ObjectAddress
324 28 : OperatorCreate(const char *operatorName,
325 : Oid operatorNamespace,
326 : Oid leftTypeId,
327 : Oid rightTypeId,
328 : Oid procedureId,
329 : List *commutatorName,
330 : List *negatorName,
331 : Oid restrictionId,
332 : Oid joinId,
333 : bool canMerge,
334 : bool canHash)
335 : {
336 : Relation pg_operator_desc;
337 : HeapTuple tup;
338 : bool isUpdate;
339 : bool nulls[Natts_pg_operator];
340 : bool replaces[Natts_pg_operator];
341 : Datum values[Natts_pg_operator];
342 : Oid operatorObjectId;
343 : bool operatorAlreadyDefined;
344 : Oid operResultType;
345 : Oid commutatorId,
346 : negatorId;
347 28 : bool selfCommutator = false;
348 : NameData oname;
349 : int i;
350 : ObjectAddress address;
351 :
352 : /*
353 : * Sanity checks
354 : */
355 28 : if (!validOperatorName(operatorName))
356 0 : ereport(ERROR,
357 : (errcode(ERRCODE_INVALID_NAME),
358 : errmsg("\"%s\" is not a valid operator name",
359 : operatorName)));
360 :
361 28 : if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
362 : {
363 : /* If it's not a binary op, these things mustn't be set: */
364 6 : if (commutatorName)
365 0 : ereport(ERROR,
366 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367 : errmsg("only binary operators can have commutators")));
368 6 : if (OidIsValid(joinId))
369 0 : ereport(ERROR,
370 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 : errmsg("only binary operators can have join selectivity")));
372 6 : if (canMerge)
373 0 : ereport(ERROR,
374 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375 : errmsg("only binary operators can merge join")));
376 6 : if (canHash)
377 0 : ereport(ERROR,
378 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379 : errmsg("only binary operators can hash")));
380 : }
381 :
382 28 : operResultType = get_func_rettype(procedureId);
383 :
384 28 : if (operResultType != BOOLOID)
385 : {
386 : /* If it's not a boolean op, these things mustn't be set: */
387 10 : if (negatorName)
388 0 : ereport(ERROR,
389 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
390 : errmsg("only boolean operators can have negators")));
391 10 : if (OidIsValid(restrictionId))
392 0 : ereport(ERROR,
393 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394 : errmsg("only boolean operators can have restriction selectivity")));
395 10 : if (OidIsValid(joinId))
396 0 : ereport(ERROR,
397 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398 : errmsg("only boolean operators can have join selectivity")));
399 10 : if (canMerge)
400 0 : ereport(ERROR,
401 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402 : errmsg("only boolean operators can merge join")));
403 10 : if (canHash)
404 0 : ereport(ERROR,
405 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406 : errmsg("only boolean operators can hash")));
407 : }
408 :
409 28 : operatorObjectId = OperatorGet(operatorName,
410 : operatorNamespace,
411 : leftTypeId,
412 : rightTypeId,
413 : &operatorAlreadyDefined);
414 :
415 28 : if (operatorAlreadyDefined)
416 0 : ereport(ERROR,
417 : (errcode(ERRCODE_DUPLICATE_FUNCTION),
418 : errmsg("operator %s already exists",
419 : operatorName)));
420 :
421 : /*
422 : * At this point, if operatorObjectId is not InvalidOid then we are
423 : * filling in a previously-created shell. Insist that the user own any
424 : * such shell.
425 : */
426 28 : if (OidIsValid(operatorObjectId) &&
427 0 : !pg_oper_ownercheck(operatorObjectId, GetUserId()))
428 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
429 : operatorName);
430 :
431 : /*
432 : * Set up the other operators. If they do not currently exist, create
433 : * shells in order to get ObjectId's.
434 : */
435 :
436 28 : if (commutatorName)
437 : {
438 : /* commutator has reversed arg types */
439 9 : commutatorId = get_other_operator(commutatorName,
440 : rightTypeId, leftTypeId,
441 : operatorName, operatorNamespace,
442 : leftTypeId, rightTypeId,
443 : true);
444 :
445 : /* Permission check: must own other operator */
446 11 : if (OidIsValid(commutatorId) &&
447 2 : !pg_oper_ownercheck(commutatorId, GetUserId()))
448 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
449 0 : NameListToString(commutatorName));
450 :
451 : /*
452 : * self-linkage to this operator; will fix below. Note that only
453 : * self-linkage for commutation makes sense.
454 : */
455 9 : if (!OidIsValid(commutatorId))
456 7 : selfCommutator = true;
457 : }
458 : else
459 19 : commutatorId = InvalidOid;
460 :
461 28 : if (negatorName)
462 : {
463 : /* negator has same arg types */
464 5 : negatorId = get_other_operator(negatorName,
465 : leftTypeId, rightTypeId,
466 : operatorName, operatorNamespace,
467 : leftTypeId, rightTypeId,
468 : false);
469 :
470 : /* Permission check: must own other operator */
471 10 : if (OidIsValid(negatorId) &&
472 5 : !pg_oper_ownercheck(negatorId, GetUserId()))
473 0 : aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
474 0 : NameListToString(negatorName));
475 : }
476 : else
477 23 : negatorId = InvalidOid;
478 :
479 : /*
480 : * set up values in the operator tuple
481 : */
482 :
483 420 : for (i = 0; i < Natts_pg_operator; ++i)
484 : {
485 392 : values[i] = (Datum) NULL;
486 392 : replaces[i] = true;
487 392 : nulls[i] = false;
488 : }
489 :
490 28 : namestrcpy(&oname, operatorName);
491 28 : values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
492 28 : values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
493 28 : values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
494 28 : values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
495 28 : values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
496 28 : values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
497 28 : values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
498 28 : values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
499 28 : values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
500 28 : values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
501 28 : values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
502 28 : values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
503 28 : values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
504 28 : values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
505 :
506 28 : pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
507 :
508 : /*
509 : * If we are replacing an operator shell, update; else insert
510 : */
511 28 : if (operatorObjectId)
512 : {
513 0 : isUpdate = true;
514 :
515 0 : tup = SearchSysCacheCopy1(OPEROID,
516 : ObjectIdGetDatum(operatorObjectId));
517 0 : if (!HeapTupleIsValid(tup))
518 0 : elog(ERROR, "cache lookup failed for operator %u",
519 : operatorObjectId);
520 :
521 0 : tup = heap_modify_tuple(tup,
522 : RelationGetDescr(pg_operator_desc),
523 : values,
524 : nulls,
525 : replaces);
526 :
527 0 : CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
528 : }
529 : else
530 : {
531 28 : isUpdate = false;
532 :
533 28 : tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
534 : values, nulls);
535 :
536 28 : operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
537 : }
538 :
539 : /* Add dependencies for the entry */
540 28 : address = makeOperatorDependencies(tup, isUpdate);
541 :
542 : /* Post creation hook for new operator */
543 28 : InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
544 :
545 28 : heap_close(pg_operator_desc, RowExclusiveLock);
546 :
547 : /*
548 : * If a commutator and/or negator link is provided, update the other
549 : * operator(s) to point at this one, if they don't already have a link.
550 : * This supports an alternative style of operator definition wherein the
551 : * user first defines one operator without giving negator or commutator,
552 : * then defines the other operator of the pair with the proper commutator
553 : * or negator attribute. That style doesn't require creation of a shell,
554 : * and it's the only style that worked right before Postgres version 6.5.
555 : * This code also takes care of the situation where the new operator is
556 : * its own commutator.
557 : */
558 28 : if (selfCommutator)
559 7 : commutatorId = operatorObjectId;
560 :
561 28 : if (OidIsValid(commutatorId) || OidIsValid(negatorId))
562 9 : OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
563 :
564 28 : return address;
565 : }
566 :
567 : /*
568 : * Try to lookup another operator (commutator, etc)
569 : *
570 : * If not found, check to see if it is exactly the operator we are trying
571 : * to define; if so, return InvalidOid. (Note that this case is only
572 : * sensible for a commutator, so we error out otherwise.) If it is not
573 : * the same operator, create a shell operator.
574 : */
575 : static Oid
576 14 : get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
577 : const char *operatorName, Oid operatorNamespace,
578 : Oid leftTypeId, Oid rightTypeId, bool isCommutator)
579 : {
580 : Oid other_oid;
581 : bool otherDefined;
582 : char *otherName;
583 : Oid otherNamespace;
584 : AclResult aclresult;
585 :
586 14 : other_oid = OperatorLookup(otherOp,
587 : otherLeftTypeId,
588 : otherRightTypeId,
589 : &otherDefined);
590 :
591 14 : if (OidIsValid(other_oid))
592 : {
593 : /* other op already in catalogs */
594 3 : return other_oid;
595 : }
596 :
597 11 : otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
598 : &otherName);
599 :
600 11 : if (strcmp(otherName, operatorName) == 0 &&
601 7 : otherNamespace == operatorNamespace &&
602 7 : otherLeftTypeId == leftTypeId &&
603 : otherRightTypeId == rightTypeId)
604 : {
605 : /*
606 : * self-linkage to this operator; caller will fix later. Note that
607 : * only self-linkage for commutation makes sense.
608 : */
609 7 : if (!isCommutator)
610 0 : ereport(ERROR,
611 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
612 : errmsg("operator cannot be its own negator or sort operator")));
613 7 : return InvalidOid;
614 : }
615 :
616 : /* not in catalogs, different from operator, so make shell */
617 :
618 4 : aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
619 : ACL_CREATE);
620 4 : if (aclresult != ACLCHECK_OK)
621 0 : aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
622 0 : get_namespace_name(otherNamespace));
623 :
624 4 : other_oid = OperatorShellMake(otherName,
625 : otherNamespace,
626 : otherLeftTypeId,
627 : otherRightTypeId);
628 4 : return other_oid;
629 : }
630 :
631 : /*
632 : * OperatorUpd
633 : *
634 : * For a given operator, look up its negator and commutator operators.
635 : * When isDelete is false, update their negator and commutator fields to
636 : * point back to the given operator; when isDelete is true, update those
637 : * fields to no longer point back to the given operator.
638 : *
639 : * The !isDelete case solves a problem for users who need to insert two new
640 : * operators that are the negator or commutator of each other, while the
641 : * isDelete case is needed so as not to leave dangling OID links behind
642 : * after dropping an operator.
643 : */
644 : void
645 13 : OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
646 : {
647 : Relation pg_operator_desc;
648 : HeapTuple tup;
649 :
650 : /*
651 : * If we're making an operator into its own commutator, then we need a
652 : * command-counter increment here, since we've just inserted the tuple
653 : * we're about to update. But when we're dropping an operator, we can
654 : * skip this because we're at the beginning of the command.
655 : */
656 13 : if (!isDelete)
657 9 : CommandCounterIncrement();
658 :
659 : /* Open the relation. */
660 13 : pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
661 :
662 : /* Get a writable copy of the commutator's tuple. */
663 13 : if (OidIsValid(commId))
664 13 : tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
665 : else
666 0 : tup = NULL;
667 :
668 : /* Update the commutator's tuple if need be. */
669 13 : if (HeapTupleIsValid(tup))
670 : {
671 13 : Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
672 13 : bool update_commutator = false;
673 :
674 : /*
675 : * Out of due caution, we only change the commutator's oprcom field if
676 : * it has the exact value we expected: InvalidOid when creating an
677 : * operator, or baseId when dropping one.
678 : */
679 13 : if (isDelete && t->oprcom == baseId)
680 : {
681 4 : t->oprcom = InvalidOid;
682 4 : update_commutator = true;
683 : }
684 9 : else if (!isDelete && !OidIsValid(t->oprcom))
685 : {
686 9 : t->oprcom = baseId;
687 9 : update_commutator = true;
688 : }
689 :
690 : /* If any columns were found to need modification, update tuple. */
691 13 : if (update_commutator)
692 : {
693 13 : CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
694 :
695 : /*
696 : * Do CCI to make the updated tuple visible. We must do this in
697 : * case the commutator is also the negator. (Which would be a
698 : * logic error on the operator definer's part, but that's not a
699 : * good reason to fail here.) We would need a CCI anyway in the
700 : * deletion case for a self-commutator with no negator.
701 : */
702 13 : CommandCounterIncrement();
703 : }
704 : }
705 :
706 : /*
707 : * Similarly find and update the negator, if any.
708 : */
709 13 : if (OidIsValid(negId))
710 8 : tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
711 : else
712 5 : tup = NULL;
713 :
714 13 : if (HeapTupleIsValid(tup))
715 : {
716 8 : Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
717 8 : bool update_negator = false;
718 :
719 : /*
720 : * Out of due caution, we only change the negator's oprnegate field if
721 : * it has the exact value we expected: InvalidOid when creating an
722 : * operator, or baseId when dropping one.
723 : */
724 8 : if (isDelete && t->oprnegate == baseId)
725 : {
726 3 : t->oprnegate = InvalidOid;
727 3 : update_negator = true;
728 : }
729 5 : else if (!isDelete && !OidIsValid(t->oprnegate))
730 : {
731 5 : t->oprnegate = baseId;
732 5 : update_negator = true;
733 : }
734 :
735 : /* If any columns were found to need modification, update tuple. */
736 8 : if (update_negator)
737 : {
738 8 : CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
739 :
740 : /*
741 : * In the deletion case, do CCI to make the updated tuple visible.
742 : * We must do this in case the operator is its own negator. (Which
743 : * would be a logic error on the operator definer's part, but
744 : * that's not a good reason to fail here.)
745 : */
746 8 : if (isDelete)
747 3 : CommandCounterIncrement();
748 : }
749 : }
750 :
751 : /* Close relation and release catalog lock. */
752 13 : heap_close(pg_operator_desc, RowExclusiveLock);
753 13 : }
754 :
755 : /*
756 : * Create dependencies for an operator (either a freshly inserted
757 : * complete operator, a new shell operator, a just-updated shell,
758 : * or an operator that's being modified by ALTER OPERATOR).
759 : *
760 : * NB: the OidIsValid tests in this routine are necessary, in case
761 : * the given operator is a shell.
762 : */
763 : ObjectAddress
764 38 : makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
765 : {
766 38 : Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
767 : ObjectAddress myself,
768 : referenced;
769 :
770 38 : myself.classId = OperatorRelationId;
771 38 : myself.objectId = HeapTupleGetOid(tuple);
772 38 : myself.objectSubId = 0;
773 :
774 : /*
775 : * If we are updating the operator, delete any existing entries, except
776 : * for extension membership which should remain the same.
777 : */
778 38 : if (isUpdate)
779 : {
780 6 : deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
781 6 : deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
782 : }
783 :
784 : /* Dependency on namespace */
785 38 : if (OidIsValid(oper->oprnamespace))
786 : {
787 38 : referenced.classId = NamespaceRelationId;
788 38 : referenced.objectId = oper->oprnamespace;
789 38 : referenced.objectSubId = 0;
790 38 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
791 : }
792 :
793 : /* Dependency on left type */
794 38 : if (OidIsValid(oper->oprleft))
795 : {
796 35 : referenced.classId = TypeRelationId;
797 35 : referenced.objectId = oper->oprleft;
798 35 : referenced.objectSubId = 0;
799 35 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
800 : }
801 :
802 : /* Dependency on right type */
803 38 : if (OidIsValid(oper->oprright))
804 : {
805 35 : referenced.classId = TypeRelationId;
806 35 : referenced.objectId = oper->oprright;
807 35 : referenced.objectSubId = 0;
808 35 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
809 : }
810 :
811 : /* Dependency on result type */
812 38 : if (OidIsValid(oper->oprresult))
813 : {
814 34 : referenced.classId = TypeRelationId;
815 34 : referenced.objectId = oper->oprresult;
816 34 : referenced.objectSubId = 0;
817 34 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
818 : }
819 :
820 : /*
821 : * NOTE: we do not consider the operator to depend on the associated
822 : * operators oprcom and oprnegate. We would not want to delete this
823 : * operator if those go away, but only reset the link fields; which is not
824 : * a function that the dependency code can presently handle. (Something
825 : * could perhaps be done with objectSubId though.) For now, it's okay to
826 : * let those links dangle if a referenced operator is removed.
827 : */
828 :
829 : /* Dependency on implementation function */
830 38 : if (OidIsValid(oper->oprcode))
831 : {
832 34 : referenced.classId = ProcedureRelationId;
833 34 : referenced.objectId = oper->oprcode;
834 34 : referenced.objectSubId = 0;
835 34 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
836 : }
837 :
838 : /* Dependency on restriction selectivity function */
839 38 : if (OidIsValid(oper->oprrest))
840 : {
841 11 : referenced.classId = ProcedureRelationId;
842 11 : referenced.objectId = oper->oprrest;
843 11 : referenced.objectSubId = 0;
844 11 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845 : }
846 :
847 : /* Dependency on join selectivity function */
848 38 : if (OidIsValid(oper->oprjoin))
849 : {
850 9 : referenced.classId = ProcedureRelationId;
851 9 : referenced.objectId = oper->oprjoin;
852 9 : referenced.objectSubId = 0;
853 9 : recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
854 : }
855 :
856 : /* Dependency on owner */
857 38 : recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
858 : oper->oprowner);
859 :
860 : /* Dependency on extension */
861 38 : recordDependencyOnCurrentExtension(&myself, true);
862 :
863 38 : return myself;
864 : }
|