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