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