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
validOperatorName(const char * name)74 validOperatorName(const char *name)
75 {
76 	size_t		len = strlen(name);
77 
78 	/* Can't be empty or too long */
79 	if (len == 0 || len >= NAMEDATALEN)
80 		return false;
81 
82 	/* Can't contain any invalid characters */
83 	/* Test string here should match op_chars in scan.l */
84 	if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
85 		return false;
86 
87 	/* Can't contain slash-star or dash-dash (comment starts) */
88 	if (strstr(name, "/*") || strstr(name, "--"))
89 		return false;
90 
91 	/*
92 	 * For SQL standard compatibility, '+' and '-' cannot be the last char of
93 	 * a multi-char operator unless the operator contains chars that are not
94 	 * in SQL operators. The idea is to lex '=-' as two operators, but not to
95 	 * forbid operator names like '?-' that could not be sequences of standard
96 	 * SQL operators.
97 	 */
98 	if (len > 1 &&
99 		(name[len - 1] == '+' ||
100 		 name[len - 1] == '-'))
101 	{
102 		int			ic;
103 
104 		for (ic = len - 2; ic >= 0; ic--)
105 		{
106 			if (strchr("~!@#^&|`?%", name[ic]))
107 				break;
108 		}
109 		if (ic < 0)
110 			return false;		/* nope, not valid */
111 	}
112 
113 	/* != isn't valid either, because parser will convert it to <> */
114 	if (strcmp(name, "!=") == 0)
115 		return false;
116 
117 	return true;
118 }
119 
120 
121 /*
122  * OperatorGet
123  *
124  *		finds an operator given an exact specification (name, namespace,
125  *		left and right type IDs).
126  *
127  *		*defined is set TRUE if defined (not a shell)
128  */
129 static Oid
OperatorGet(const char * operatorName,Oid operatorNamespace,Oid leftObjectId,Oid rightObjectId,bool * defined)130 OperatorGet(const char *operatorName,
131 			Oid operatorNamespace,
132 			Oid leftObjectId,
133 			Oid rightObjectId,
134 			bool *defined)
135 {
136 	HeapTuple	tup;
137 	Oid			operatorObjectId;
138 
139 	tup = SearchSysCache4(OPERNAMENSP,
140 						  PointerGetDatum(operatorName),
141 						  ObjectIdGetDatum(leftObjectId),
142 						  ObjectIdGetDatum(rightObjectId),
143 						  ObjectIdGetDatum(operatorNamespace));
144 	if (HeapTupleIsValid(tup))
145 	{
146 		RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
147 
148 		operatorObjectId = HeapTupleGetOid(tup);
149 		*defined = RegProcedureIsValid(oprcode);
150 		ReleaseSysCache(tup);
151 	}
152 	else
153 	{
154 		operatorObjectId = InvalidOid;
155 		*defined = false;
156 	}
157 
158 	return operatorObjectId;
159 }
160 
161 /*
162  * OperatorLookup
163  *
164  *		looks up an operator given a possibly-qualified name and
165  *		left and right type IDs.
166  *
167  *		*defined is set TRUE if defined (not a shell)
168  */
169 static Oid
OperatorLookup(List * operatorName,Oid leftObjectId,Oid rightObjectId,bool * defined)170 OperatorLookup(List *operatorName,
171 			   Oid leftObjectId,
172 			   Oid rightObjectId,
173 			   bool *defined)
174 {
175 	Oid			operatorObjectId;
176 	RegProcedure oprcode;
177 
178 	operatorObjectId = LookupOperName(NULL, operatorName,
179 									  leftObjectId, rightObjectId,
180 									  true, -1);
181 	if (!OidIsValid(operatorObjectId))
182 	{
183 		*defined = false;
184 		return InvalidOid;
185 	}
186 
187 	oprcode = get_opcode(operatorObjectId);
188 	*defined = RegProcedureIsValid(oprcode);
189 
190 	return operatorObjectId;
191 }
192 
193 
194 /*
195  * OperatorShellMake
196  *		Make a "shell" entry for a not-yet-existing operator.
197  */
198 static Oid
OperatorShellMake(const char * operatorName,Oid operatorNamespace,Oid leftTypeId,Oid rightTypeId)199 OperatorShellMake(const char *operatorName,
200 				  Oid operatorNamespace,
201 				  Oid leftTypeId,
202 				  Oid rightTypeId)
203 {
204 	Relation	pg_operator_desc;
205 	Oid			operatorObjectId;
206 	int			i;
207 	HeapTuple	tup;
208 	Datum		values[Natts_pg_operator];
209 	bool		nulls[Natts_pg_operator];
210 	NameData	oname;
211 	TupleDesc	tupDesc;
212 
213 	/*
214 	 * validate operator name
215 	 */
216 	if (!validOperatorName(operatorName))
217 		ereport(ERROR,
218 				(errcode(ERRCODE_INVALID_NAME),
219 				 errmsg("\"%s\" is not a valid operator name",
220 						operatorName)));
221 
222 	/*
223 	 * 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 	namestrcpy(&oname, operatorName);
236 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
237 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
238 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
239 	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
240 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
241 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
242 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
243 	values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
244 	values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
245 	values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
246 	values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
247 	values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
248 	values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
249 	values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
250 
251 	/*
252 	 * open pg_operator
253 	 */
254 	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
255 	tupDesc = pg_operator_desc->rd_att;
256 
257 	/*
258 	 * create a new operator tuple
259 	 */
260 	tup = heap_form_tuple(tupDesc, values, nulls);
261 
262 	/*
263 	 * insert our "shell" operator tuple
264 	 */
265 	operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
266 
267 	/* Add dependencies for the entry */
268 	makeOperatorDependencies(tup, false);
269 
270 	heap_freetuple(tup);
271 
272 	/* Post creation hook for new shell operator */
273 	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
274 
275 	/*
276 	 * Make sure the tuple is visible for subsequent lookups/updates.
277 	 */
278 	CommandCounterIncrement();
279 
280 	/*
281 	 * close the operator relation and return the oid.
282 	 */
283 	heap_close(pg_operator_desc, RowExclusiveLock);
284 
285 	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
OperatorCreate(const char * operatorName,Oid operatorNamespace,Oid leftTypeId,Oid rightTypeId,Oid procedureId,List * commutatorName,List * negatorName,Oid restrictionId,Oid joinId,bool canMerge,bool canHash)324 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 	bool		selfCommutator = false;
348 	NameData	oname;
349 	int			i;
350 	ObjectAddress address;
351 
352 	/*
353 	 * Sanity checks
354 	 */
355 	if (!validOperatorName(operatorName))
356 		ereport(ERROR,
357 				(errcode(ERRCODE_INVALID_NAME),
358 				 errmsg("\"%s\" is not a valid operator name",
359 						operatorName)));
360 
361 	if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
362 	{
363 		/* If it's not a binary op, these things mustn't be set: */
364 		if (commutatorName)
365 			ereport(ERROR,
366 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367 					 errmsg("only binary operators can have commutators")));
368 		if (OidIsValid(joinId))
369 			ereport(ERROR,
370 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371 					 errmsg("only binary operators can have join selectivity")));
372 		if (canMerge)
373 			ereport(ERROR,
374 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375 					 errmsg("only binary operators can merge join")));
376 		if (canHash)
377 			ereport(ERROR,
378 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379 					 errmsg("only binary operators can hash")));
380 	}
381 
382 	operResultType = get_func_rettype(procedureId);
383 
384 	if (operResultType != BOOLOID)
385 	{
386 		/* If it's not a boolean op, these things mustn't be set: */
387 		if (negatorName)
388 			ereport(ERROR,
389 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
390 					 errmsg("only boolean operators can have negators")));
391 		if (OidIsValid(restrictionId))
392 			ereport(ERROR,
393 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394 					 errmsg("only boolean operators can have restriction selectivity")));
395 		if (OidIsValid(joinId))
396 			ereport(ERROR,
397 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398 					 errmsg("only boolean operators can have join selectivity")));
399 		if (canMerge)
400 			ereport(ERROR,
401 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402 					 errmsg("only boolean operators can merge join")));
403 		if (canHash)
404 			ereport(ERROR,
405 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406 					 errmsg("only boolean operators can hash")));
407 	}
408 
409 	operatorObjectId = OperatorGet(operatorName,
410 								   operatorNamespace,
411 								   leftTypeId,
412 								   rightTypeId,
413 								   &operatorAlreadyDefined);
414 
415 	if (operatorAlreadyDefined)
416 		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 	if (OidIsValid(operatorObjectId) &&
427 		!pg_oper_ownercheck(operatorObjectId, GetUserId()))
428 		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 	if (commutatorName)
437 	{
438 		/* commutator has reversed arg types */
439 		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 		if (OidIsValid(commutatorId) &&
447 			!pg_oper_ownercheck(commutatorId, GetUserId()))
448 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
449 						   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 		if (!OidIsValid(commutatorId))
456 			selfCommutator = true;
457 	}
458 	else
459 		commutatorId = InvalidOid;
460 
461 	if (negatorName)
462 	{
463 		/* negator has same arg types */
464 		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 		if (OidIsValid(negatorId) &&
472 			!pg_oper_ownercheck(negatorId, GetUserId()))
473 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
474 						   NameListToString(negatorName));
475 	}
476 	else
477 		negatorId = InvalidOid;
478 
479 	/*
480 	 * set up values in the operator tuple
481 	 */
482 
483 	for (i = 0; i < Natts_pg_operator; ++i)
484 	{
485 		values[i] = (Datum) NULL;
486 		replaces[i] = true;
487 		nulls[i] = false;
488 	}
489 
490 	namestrcpy(&oname, operatorName);
491 	values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
492 	values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
493 	values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
494 	values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
495 	values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
496 	values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
497 	values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
498 	values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
499 	values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
500 	values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
501 	values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
502 	values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
503 	values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
504 	values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
505 
506 	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
507 
508 	/*
509 	 * If we are replacing an operator shell, update; else insert
510 	 */
511 	if (operatorObjectId)
512 	{
513 		isUpdate = true;
514 
515 		tup = SearchSysCacheCopy1(OPEROID,
516 								  ObjectIdGetDatum(operatorObjectId));
517 		if (!HeapTupleIsValid(tup))
518 			elog(ERROR, "cache lookup failed for operator %u",
519 				 operatorObjectId);
520 
521 		tup = heap_modify_tuple(tup,
522 								RelationGetDescr(pg_operator_desc),
523 								values,
524 								nulls,
525 								replaces);
526 
527 		CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
528 	}
529 	else
530 	{
531 		isUpdate = false;
532 
533 		tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
534 							  values, nulls);
535 
536 		operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
537 	}
538 
539 	/* Add dependencies for the entry */
540 	address = makeOperatorDependencies(tup, isUpdate);
541 
542 	/* Post creation hook for new operator */
543 	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
544 
545 	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 	if (selfCommutator)
559 		commutatorId = operatorObjectId;
560 
561 	if (OidIsValid(commutatorId) || OidIsValid(negatorId))
562 		OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
563 
564 	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
get_other_operator(List * otherOp,Oid otherLeftTypeId,Oid otherRightTypeId,const char * operatorName,Oid operatorNamespace,Oid leftTypeId,Oid rightTypeId,bool isCommutator)576 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 	other_oid = OperatorLookup(otherOp,
587 							   otherLeftTypeId,
588 							   otherRightTypeId,
589 							   &otherDefined);
590 
591 	if (OidIsValid(other_oid))
592 	{
593 		/* other op already in catalogs */
594 		return other_oid;
595 	}
596 
597 	otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
598 													   &otherName);
599 
600 	if (strcmp(otherName, operatorName) == 0 &&
601 		otherNamespace == operatorNamespace &&
602 		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 		if (!isCommutator)
610 			ereport(ERROR,
611 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
612 					 errmsg("operator cannot be its own negator or sort operator")));
613 		return InvalidOid;
614 	}
615 
616 	/* not in catalogs, different from operator, so make shell */
617 
618 	aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
619 									  ACL_CREATE);
620 	if (aclresult != ACLCHECK_OK)
621 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
622 					   get_namespace_name(otherNamespace));
623 
624 	other_oid = OperatorShellMake(otherName,
625 								  otherNamespace,
626 								  otherLeftTypeId,
627 								  otherRightTypeId);
628 	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
OperatorUpd(Oid baseId,Oid commId,Oid negId,bool isDelete)645 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 	if (!isDelete)
657 		CommandCounterIncrement();
658 
659 	/* Open the relation. */
660 	pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
661 
662 	/* Get a writable copy of the commutator's tuple. */
663 	if (OidIsValid(commId))
664 		tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
665 	else
666 		tup = NULL;
667 
668 	/* Update the commutator's tuple if need be. */
669 	if (HeapTupleIsValid(tup))
670 	{
671 		Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
672 		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 		if (isDelete && t->oprcom == baseId)
680 		{
681 			t->oprcom = InvalidOid;
682 			update_commutator = true;
683 		}
684 		else if (!isDelete && !OidIsValid(t->oprcom))
685 		{
686 			t->oprcom = baseId;
687 			update_commutator = true;
688 		}
689 
690 		/* If any columns were found to need modification, update tuple. */
691 		if (update_commutator)
692 		{
693 			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 			CommandCounterIncrement();
703 		}
704 	}
705 
706 	/*
707 	 * Similarly find and update the negator, if any.
708 	 */
709 	if (OidIsValid(negId))
710 		tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
711 	else
712 		tup = NULL;
713 
714 	if (HeapTupleIsValid(tup))
715 	{
716 		Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
717 		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 		if (isDelete && t->oprnegate == baseId)
725 		{
726 			t->oprnegate = InvalidOid;
727 			update_negator = true;
728 		}
729 		else if (!isDelete && !OidIsValid(t->oprnegate))
730 		{
731 			t->oprnegate = baseId;
732 			update_negator = true;
733 		}
734 
735 		/* If any columns were found to need modification, update tuple. */
736 		if (update_negator)
737 		{
738 			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 			if (isDelete)
747 				CommandCounterIncrement();
748 		}
749 	}
750 
751 	/* Close relation and release catalog lock. */
752 	heap_close(pg_operator_desc, RowExclusiveLock);
753 }
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
makeOperatorDependencies(HeapTuple tuple,bool isUpdate)764 makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
765 {
766 	Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
767 	ObjectAddress myself,
768 				referenced;
769 
770 	myself.classId = OperatorRelationId;
771 	myself.objectId = HeapTupleGetOid(tuple);
772 	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 	if (isUpdate)
779 	{
780 		deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
781 		deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
782 	}
783 
784 	/* Dependency on namespace */
785 	if (OidIsValid(oper->oprnamespace))
786 	{
787 		referenced.classId = NamespaceRelationId;
788 		referenced.objectId = oper->oprnamespace;
789 		referenced.objectSubId = 0;
790 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
791 	}
792 
793 	/* Dependency on left type */
794 	if (OidIsValid(oper->oprleft))
795 	{
796 		referenced.classId = TypeRelationId;
797 		referenced.objectId = oper->oprleft;
798 		referenced.objectSubId = 0;
799 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
800 	}
801 
802 	/* Dependency on right type */
803 	if (OidIsValid(oper->oprright))
804 	{
805 		referenced.classId = TypeRelationId;
806 		referenced.objectId = oper->oprright;
807 		referenced.objectSubId = 0;
808 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
809 	}
810 
811 	/* Dependency on result type */
812 	if (OidIsValid(oper->oprresult))
813 	{
814 		referenced.classId = TypeRelationId;
815 		referenced.objectId = oper->oprresult;
816 		referenced.objectSubId = 0;
817 		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 	if (OidIsValid(oper->oprcode))
831 	{
832 		referenced.classId = ProcedureRelationId;
833 		referenced.objectId = oper->oprcode;
834 		referenced.objectSubId = 0;
835 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
836 	}
837 
838 	/* Dependency on restriction selectivity function */
839 	if (OidIsValid(oper->oprrest))
840 	{
841 		referenced.classId = ProcedureRelationId;
842 		referenced.objectId = oper->oprrest;
843 		referenced.objectSubId = 0;
844 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845 	}
846 
847 	/* Dependency on join selectivity function */
848 	if (OidIsValid(oper->oprjoin))
849 	{
850 		referenced.classId = ProcedureRelationId;
851 		referenced.objectId = oper->oprjoin;
852 		referenced.objectSubId = 0;
853 		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
854 	}
855 
856 	/* Dependency on owner */
857 	recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
858 							oper->oprowner);
859 
860 	/* Dependency on extension */
861 	recordDependencyOnCurrentExtension(&myself, true);
862 
863 	return myself;
864 }
865