Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_operator.c
4 : * routines to support manipulation of the pg_operator relation
5 : *
6 : * Portions Copyright (c) 1996-2023, 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
7839 tgl 74 CBC 972 : validOperatorName(const char *name)
75 : {
7836 bruce 76 972 : size_t len = strlen(name);
77 :
78 : /* Can't be empty or too long */
7839 tgl 79 972 : if (len == 0 || len >= NAMEDATALEN)
7839 tgl 80 UBC 0 : return false;
81 :
82 : /* Can't contain any invalid characters */
83 : /* Test string here should match op_chars in scan.l */
7202 tgl 84 CBC 972 : if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
7839 tgl 85 UBC 0 : return false;
86 :
87 : /* Can't contain slash-star or dash-dash (comment starts) */
7839 tgl 88 CBC 972 : if (strstr(name, "/*") || strstr(name, "--"))
7839 tgl 89 UBC 0 : return false;
90 :
91 : /*
92 : * For SQL standard compatibility, '+' and '-' cannot be the last char of
93 : * a multi-char operator unless the operator contains chars that are not
94 : * in SQL operators. The idea is to lex '=-' as two operators, but not to
95 : * forbid operator names like '?-' that could not be sequences of standard
96 : * SQL operators.
97 : */
7839 tgl 98 CBC 972 : if (len > 1 &&
7836 bruce 99 650 : (name[len - 1] == '+' ||
100 650 : name[len - 1] == '-'))
101 : {
102 : int ic;
103 :
104 8 : for (ic = len - 2; ic >= 0; ic--)
105 : {
7202 tgl 106 8 : if (strchr("~!@#^&|`?%", name[ic]))
7839 107 4 : break;
108 : }
109 4 : if (ic < 0)
7839 tgl 110 UBC 0 : return false; /* nope, not valid */
111 : }
112 :
113 : /* != isn't valid either, because parser will convert it to <> */
7839 tgl 114 CBC 972 : if (strcmp(name, "!=") == 0)
7839 tgl 115 UBC 0 : return false;
116 :
7839 tgl 117 CBC 972 : 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
7681 130 706 : OperatorGet(const char *operatorName,
131 : Oid operatorNamespace,
132 : Oid leftObjectId,
133 : Oid rightObjectId,
134 : bool *defined)
135 : {
136 : HeapTuple tup;
137 : Oid operatorObjectId;
138 :
4802 rhaas 139 706 : tup = SearchSysCache4(OPERNAMENSP,
140 : PointerGetDatum(operatorName),
141 : ObjectIdGetDatum(leftObjectId),
142 : ObjectIdGetDatum(rightObjectId),
143 : ObjectIdGetDatum(operatorNamespace));
8764 tgl 144 706 : if (HeapTupleIsValid(tup))
145 : {
1601 andres 146 252 : Form_pg_operator oprform = (Form_pg_operator) GETSTRUCT(tup);
147 :
148 252 : operatorObjectId = oprform->oid;
149 252 : *defined = RegProcedureIsValid(oprform->oprcode);
7663 tgl 150 252 : ReleaseSysCache(tup);
151 : }
152 : else
153 : {
8764 154 454 : operatorObjectId = InvalidOid;
155 454 : *defined = false;
156 : }
157 :
7663 158 706 : return operatorObjectId;
159 : }
160 :
161 : /*
162 : * OperatorLookup
163 : *
164 : * looks up an operator given a possibly-qualified name and
165 : * left and right type IDs.
166 : *
167 : * *defined is set true if defined (not a shell)
168 : */
169 : static Oid
170 794 : OperatorLookup(List *operatorName,
171 : Oid leftObjectId,
172 : Oid rightObjectId,
173 : bool *defined)
174 : {
175 : Oid operatorObjectId;
176 : RegProcedure oprcode;
177 :
6235 178 794 : operatorObjectId = LookupOperName(NULL, operatorName,
179 : leftObjectId, rightObjectId,
180 : true, -1);
7663 181 794 : if (!OidIsValid(operatorObjectId))
182 : {
183 354 : *defined = false;
184 354 : return InvalidOid;
185 : }
186 :
187 440 : oprcode = get_opcode(operatorObjectId);
188 440 : *defined = RegProcedureIsValid(oprcode);
189 :
8831 bruce 190 440 : return operatorObjectId;
191 : }
192 :
193 :
194 : /*
195 : * OperatorShellMake
196 : * Make a "shell" entry for a not-yet-existing operator.
197 : */
198 : static Oid
7681 tgl 199 266 : 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 : */
7839 216 266 : if (!validOperatorName(operatorName))
7202 tgl 217 UBC 0 : 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 : */
1539 andres 225 CBC 266 : pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
1601 226 266 : tupDesc = pg_operator_desc->rd_att;
227 :
228 : /*
229 : * initialize our *nulls and *values arrays
230 : */
9345 bruce 231 4256 : for (i = 0; i < Natts_pg_operator; ++i)
232 : {
5271 tgl 233 3990 : nulls[i] = false;
2118 234 3990 : 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 : */
1601 andres 241 266 : operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId,
242 : Anum_pg_operator_oid);
243 266 : values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
9139 scrappy 244 266 : namestrcpy(&oname, operatorName);
4315 tgl 245 266 : values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
246 266 : values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
247 266 : values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
934 248 266 : values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
4315 249 266 : values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
250 266 : values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
251 266 : values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
252 266 : values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
253 266 : values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
254 266 : values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
255 266 : values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
256 266 : values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
257 266 : values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
258 266 : values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
259 :
260 : /*
261 : * create a new operator tuple
262 : */
5271 263 266 : tup = heap_form_tuple(tupDesc, values, nulls);
264 :
265 : /*
266 : * insert our "shell" operator tuple
267 : */
1601 andres 268 266 : CatalogTupleInsert(pg_operator_desc, tup);
269 :
270 : /* Add dependencies for the entry */
600 tgl 271 266 : makeOperatorDependencies(tup, true, false);
272 :
8515 JanWieck 273 266 : heap_freetuple(tup);
274 :
275 : /* Post creation hook for new shell operator */
3686 rhaas 276 266 : InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
277 :
278 : /*
279 : * Make sure the tuple is visible for subsequent lookups/updates.
280 : */
5349 tgl 281 266 : CommandCounterIncrement();
282 :
283 : /*
284 : * close the operator relation and return the oid.
285 : */
1539 andres 286 266 : table_close(pg_operator_desc, RowExclusiveLock);
287 :
8831 bruce 288 266 : 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
7663 tgl 327 706 : 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;
8764 350 706 : bool selfCommutator = false;
351 : NameData oname;
352 : int i;
353 : ObjectAddress address;
354 :
355 : /*
356 : * Sanity checks
357 : */
7681 358 706 : if (!validOperatorName(operatorName))
7202 tgl 359 UBC 0 : ereport(ERROR,
360 : (errcode(ERRCODE_INVALID_NAME),
361 : errmsg("\"%s\" is not a valid operator name",
362 : operatorName)));
363 :
7663 tgl 364 CBC 706 : if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
365 : {
366 : /* If it's not a binary op, these things mustn't be set: */
367 34 : if (commutatorName)
7202 tgl 368 UBC 0 : ereport(ERROR,
369 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
370 : errmsg("only binary operators can have commutators")));
5349 tgl 371 CBC 34 : if (OidIsValid(joinId))
7202 tgl 372 UBC 0 : ereport(ERROR,
373 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
374 : errmsg("only binary operators can have join selectivity")));
5951 tgl 375 CBC 34 : if (canMerge)
7202 tgl 376 UBC 0 : ereport(ERROR,
377 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
378 : errmsg("only binary operators can merge join")));
5951 tgl 379 CBC 34 : if (canHash)
7202 tgl 380 UBC 0 : ereport(ERROR,
381 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
382 : errmsg("only binary operators can hash")));
383 : }
384 :
5349 tgl 385 CBC 706 : operResultType = get_func_rettype(procedureId);
386 :
387 706 : if (operResultType != BOOLOID)
388 : {
389 : /* If it's not a boolean op, these things mustn't be set: */
390 153 : if (negatorName)
5349 tgl 391 UBC 0 : ereport(ERROR,
392 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393 : errmsg("only boolean operators can have negators")));
5349 tgl 394 CBC 153 : if (OidIsValid(restrictionId))
5349 tgl 395 UBC 0 : ereport(ERROR,
396 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
397 : errmsg("only boolean operators can have restriction selectivity")));
5349 tgl 398 CBC 153 : if (OidIsValid(joinId))
5349 tgl 399 UBC 0 : ereport(ERROR,
400 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
401 : errmsg("only boolean operators can have join selectivity")));
5349 tgl 402 CBC 153 : if (canMerge)
5349 tgl 403 UBC 0 : ereport(ERROR,
404 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
405 : errmsg("only boolean operators can merge join")));
5349 tgl 406 CBC 153 : if (canHash)
5349 tgl 407 UBC 0 : ereport(ERROR,
408 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
409 : errmsg("only boolean operators can hash")));
410 : }
411 :
9345 bruce 412 CBC 706 : operatorObjectId = OperatorGet(operatorName,
413 : operatorNamespace,
414 : leftTypeId,
415 : rightTypeId,
416 : &operatorAlreadyDefined);
417 :
8764 tgl 418 706 : if (operatorAlreadyDefined)
7202 tgl 419 UBC 0 : 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 : */
5349 tgl 429 CBC 706 : if (OidIsValid(operatorObjectId) &&
147 peter 430 GNC 252 : !object_ownercheck(OperatorRelationId, operatorObjectId, GetUserId()))
1954 peter_e 431 UBC 0 : 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 :
7663 tgl 439 CBC 706 : if (commutatorName)
440 : {
441 : /* commutator has reversed arg types */
442 474 : commutatorId = get_other_operator(commutatorName,
443 : rightTypeId, leftTypeId,
444 : operatorName, operatorNamespace,
445 : leftTypeId, rightTypeId,
446 : true);
447 :
448 : /* Permission check: must own other operator */
5349 449 474 : if (OidIsValid(commutatorId) &&
147 peter 450 GNC 386 : !object_ownercheck(OperatorRelationId, commutatorId, GetUserId()))
1954 peter_e 451 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
5349 tgl 452 0 : NameListToString(commutatorName));
453 :
454 : /*
455 : * self-linkage to this operator; will fix below. Note that only
456 : * self-linkage for commutation makes sense.
457 : */
7663 tgl 458 CBC 474 : if (!OidIsValid(commutatorId))
459 88 : selfCommutator = true;
460 : }
461 : else
462 232 : commutatorId = InvalidOid;
463 :
464 706 : if (negatorName)
465 : {
466 : /* negator has same arg types */
467 320 : negatorId = get_other_operator(negatorName,
468 : leftTypeId, rightTypeId,
469 : operatorName, operatorNamespace,
470 : leftTypeId, rightTypeId,
471 : false);
472 :
473 : /* Permission check: must own other operator */
5349 474 320 : if (OidIsValid(negatorId) &&
147 peter 475 GNC 320 : !object_ownercheck(OperatorRelationId, negatorId, GetUserId()))
1954 peter_e 476 UBC 0 : aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
5349 tgl 477 0 : NameListToString(negatorName));
478 : }
479 : else
7663 tgl 480 CBC 386 : negatorId = InvalidOid;
481 :
482 : /*
483 : * set up values in the operator tuple
484 : */
485 :
5349 486 11296 : for (i = 0; i < Natts_pg_operator; ++i)
487 : {
488 10590 : values[i] = (Datum) NULL;
5271 489 10590 : replaces[i] = true;
490 10590 : nulls[i] = false;
491 : }
492 :
5349 493 706 : namestrcpy(&oname, operatorName);
4315 494 706 : values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
495 706 : values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
496 706 : values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
934 497 706 : values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
4315 498 706 : values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
499 706 : values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
500 706 : values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
501 706 : values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
502 706 : values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
503 706 : values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
504 706 : values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
505 706 : values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
506 706 : values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
507 706 : values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
508 :
1539 andres 509 706 : pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
510 :
511 : /*
512 : * If we are replacing an operator shell, update; else insert
513 : */
9345 bruce 514 706 : if (operatorObjectId)
515 : {
2656 tgl 516 252 : isUpdate = true;
517 :
4802 rhaas 518 252 : tup = SearchSysCacheCopy1(OPEROID,
519 : ObjectIdGetDatum(operatorObjectId));
7663 tgl 520 252 : if (!HeapTupleIsValid(tup))
7202 tgl 521 UBC 0 : elog(ERROR, "cache lookup failed for operator %u",
522 : operatorObjectId);
523 :
1601 andres 524 CBC 252 : replaces[Anum_pg_operator_oid - 1] = false;
5271 tgl 525 252 : tup = heap_modify_tuple(tup,
526 : RelationGetDescr(pg_operator_desc),
527 : values,
528 : nulls,
529 : replaces);
530 :
2259 alvherre 531 252 : CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
532 : }
533 : else
534 : {
2656 tgl 535 454 : isUpdate = false;
536 :
1601 andres 537 454 : operatorObjectId = GetNewOidWithIndex(pg_operator_desc,
538 : OperatorOidIndexId,
539 : Anum_pg_operator_oid);
540 454 : values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
541 :
2656 tgl 542 454 : tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
543 : values, nulls);
544 :
1601 andres 545 454 : CatalogTupleInsert(pg_operator_desc, tup);
546 : }
547 :
548 : /* Add dependencies for the entry */
600 tgl 549 706 : address = makeOperatorDependencies(tup, true, isUpdate);
550 :
551 : /* Post creation hook for new operator */
3686 rhaas 552 705 : InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
553 :
1539 andres 554 705 : 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 : */
8764 tgl 567 705 : if (selfCommutator)
568 88 : commutatorId = operatorObjectId;
569 :
570 705 : if (OidIsValid(commutatorId) || OidIsValid(negatorId))
2571 571 506 : OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
572 :
2959 alvherre 573 705 : 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
7663 tgl 585 794 : 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 794 : other_oid = OperatorLookup(otherOp,
596 : otherLeftTypeId,
597 : otherRightTypeId,
598 : &otherDefined);
599 :
600 794 : if (OidIsValid(other_oid))
601 : {
602 : /* other op already in catalogs */
603 440 : return other_oid;
604 : }
605 :
606 354 : otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
607 : &otherName);
608 :
609 354 : if (strcmp(otherName, operatorName) == 0 &&
610 132 : otherNamespace == operatorNamespace &&
611 88 : 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 88 : if (!isCommutator)
7202 tgl 619 UBC 0 : ereport(ERROR,
620 : (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
621 : errmsg("operator cannot be its own negator or sort operator")));
7663 tgl 622 CBC 88 : return InvalidOid;
623 : }
624 :
625 : /* not in catalogs, different from operator, so make shell */
626 :
147 peter 627 GNC 266 : aclresult = object_aclcheck(NamespaceRelationId, otherNamespace, GetUserId(),
628 : ACL_CREATE);
7652 tgl 629 CBC 266 : if (aclresult != ACLCHECK_OK)
1954 peter_e 630 UBC 0 : aclcheck_error(aclresult, OBJECT_SCHEMA,
7191 tgl 631 0 : get_namespace_name(otherNamespace));
632 :
7663 tgl 633 CBC 266 : other_oid = OperatorShellMake(otherName,
634 : otherNamespace,
635 : otherLeftTypeId,
636 : otherRightTypeId);
637 266 : 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
2571 654 660 : 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 660 : if (!isDelete)
666 506 : CommandCounterIncrement();
667 :
668 : /* Open the relation. */
1539 andres 669 660 : pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
670 :
671 : /* Get a writable copy of the commutator's tuple. */
2571 tgl 672 660 : if (OidIsValid(commId))
673 628 : tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
674 : else
675 32 : tup = NULL;
676 :
677 : /* Update the commutator's tuple if need be. */
678 660 : if (HeapTupleIsValid(tup))
679 : {
680 628 : Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
681 628 : 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 628 : if (isDelete && t->oprcom == baseId)
689 : {
690 154 : t->oprcom = InvalidOid;
691 154 : update_commutator = true;
692 : }
693 474 : else if (!isDelete && !OidIsValid(t->oprcom))
694 : {
695 272 : t->oprcom = baseId;
696 272 : update_commutator = true;
697 : }
698 :
699 : /* If any columns were found to need modification, update tuple. */
700 628 : if (update_commutator)
701 : {
2259 alvherre 702 426 : 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 : */
2571 tgl 711 426 : CommandCounterIncrement();
712 : }
713 : }
714 :
715 : /*
716 : * Similarly find and update the negator, if any.
717 : */
718 660 : if (OidIsValid(negId))
719 428 : tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
720 : else
721 232 : tup = NULL;
722 :
723 660 : if (HeapTupleIsValid(tup))
724 : {
725 428 : Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
726 428 : 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 428 : if (isDelete && t->oprnegate == baseId)
734 : {
735 108 : t->oprnegate = InvalidOid;
736 108 : update_negator = true;
737 : }
738 320 : else if (!isDelete && !OidIsValid(t->oprnegate))
739 : {
740 168 : t->oprnegate = baseId;
741 168 : update_negator = true;
742 : }
743 :
744 : /* If any columns were found to need modification, update tuple. */
745 428 : if (update_negator)
746 : {
2259 alvherre 747 276 : 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 : */
2571 tgl 755 276 : if (isDelete)
756 108 : CommandCounterIncrement();
757 : }
758 : }
759 :
760 : /* Close relation and release catalog lock. */
1539 andres 761 660 : table_close(pg_operator_desc, RowExclusiveLock);
9770 scrappy 762 660 : }
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
600 tgl 777 1206 : makeOperatorDependencies(HeapTuple tuple,
778 : bool makeExtensionDep,
779 : bool isUpdate)
780 : {
7522 bruce 781 1206 : Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
782 : ObjectAddress myself,
783 : referenced;
784 : ObjectAddresses *addrs;
785 :
1012 michael 786 1206 : ObjectAddressSet(myself, OperatorRelationId, oper->oid);
787 :
788 : /*
789 : * If we are updating the operator, delete any existing entries, except
790 : * for extension membership which should remain the same.
791 : */
2656 tgl 792 1206 : if (isUpdate)
793 : {
794 486 : deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
795 486 : deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
796 : }
797 :
946 michael 798 1206 : addrs = new_object_addresses();
799 :
800 : /* Dependency on namespace */
7570 tgl 801 1206 : if (OidIsValid(oper->oprnamespace))
802 : {
1012 michael 803 1206 : ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace);
946 804 1206 : add_exact_object_address(&referenced, addrs);
805 : }
806 :
807 : /* Dependency on left type */
7572 tgl 808 1206 : if (OidIsValid(oper->oprleft))
809 : {
1012 michael 810 1172 : ObjectAddressSet(referenced, TypeRelationId, oper->oprleft);
946 811 1172 : add_exact_object_address(&referenced, addrs);
812 : }
813 :
814 : /* Dependency on right type */
7572 tgl 815 1206 : if (OidIsValid(oper->oprright))
816 : {
1012 michael 817 1206 : ObjectAddressSet(referenced, TypeRelationId, oper->oprright);
946 818 1206 : add_exact_object_address(&referenced, addrs);
819 : }
820 :
821 : /* Dependency on result type */
7572 tgl 822 1206 : if (OidIsValid(oper->oprresult))
823 : {
1012 michael 824 940 : ObjectAddressSet(referenced, TypeRelationId, oper->oprresult);
946 825 940 : add_exact_object_address(&referenced, addrs);
826 : }
827 :
828 : /*
829 : * NOTE: we do not consider the operator to depend on the associated
830 : * operators oprcom and oprnegate. We do not want to delete this operator
831 : * if those go away, but only reset the link fields; which is not a
832 : * function that the dependency logic can handle. (It's taken care of
833 : * manually within RemoveOperatorById, instead.)
834 : */
835 :
7572 tgl 836 ECB : /* Dependency on implementation function */
7572 tgl 837 GIC 1206 : if (OidIsValid(oper->oprcode))
7572 tgl 838 ECB : {
1012 michael 839 CBC 940 : ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode);
946 michael 840 GIC 940 : add_exact_object_address(&referenced, addrs);
841 : }
842 :
7572 tgl 843 ECB : /* Dependency on restriction selectivity function */
7572 tgl 844 GIC 1206 : if (OidIsValid(oper->oprrest))
7572 tgl 845 ECB : {
1012 michael 846 CBC 721 : ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest);
946 michael 847 GIC 721 : add_exact_object_address(&referenced, addrs);
848 : }
849 :
7572 tgl 850 ECB : /* Dependency on join selectivity function */
7572 tgl 851 GIC 1206 : if (OidIsValid(oper->oprjoin))
7572 tgl 852 ECB : {
1012 michael 853 CBC 709 : ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin);
946 michael 854 GIC 709 : add_exact_object_address(&referenced, addrs);
855 : }
6485 tgl 856 ECB :
946 michael 857 CBC 1206 : record_object_address_dependencies(&myself, addrs, DEPENDENCY_NORMAL);
946 michael 858 GIC 1206 : free_object_addresses(addrs);
859 :
6485 tgl 860 ECB : /* Dependency on owner */
1601 andres 861 GIC 1206 : recordDependencyOnOwner(OperatorRelationId, oper->oid,
862 : oper->oprowner);
863 :
4443 tgl 864 ECB : /* Dependency on extension */
600 tgl 865 CBC 1206 : if (makeExtensionDep)
244 tgl 866 GIC 972 : recordDependencyOnCurrentExtension(&myself, isUpdate);
2959 alvherre 867 ECB :
2959 alvherre 868 GIC 1205 : return myself;
869 : }
|