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