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