PostgreSQL Source Code git master
pg_operator.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "parser/parse_oper.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for pg_operator.c:

Go to the source code of this file.

Functions

static Oid OperatorGet (const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
 
static Oid OperatorShellMake (const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
 
static Oid get_other_operator (List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
 
static bool validOperatorName (const char *name)
 
Oid OperatorLookup (List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
 
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)
 
void OperatorValidateParams (Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
 
void OperatorUpd (Oid baseId, Oid commId, Oid negId, bool isDelete)
 
ObjectAddress makeOperatorDependencies (HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
 

Function Documentation

◆ get_other_operator()

static Oid get_other_operator ( List otherOp,
Oid  otherLeftTypeId,
Oid  otherRightTypeId,
const char *  operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 622 of file pg_operator.c.

625{
626 Oid other_oid;
627 bool otherDefined;
628 char *otherName;
629 Oid otherNamespace;
630 AclResult aclresult;
631
632 other_oid = OperatorLookup(otherOp,
633 otherLeftTypeId,
634 otherRightTypeId,
635 &otherDefined);
636
637 if (OidIsValid(other_oid))
638 {
639 /* other op already in catalogs */
640 return other_oid;
641 }
642
643 otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
644 &otherName);
645
646 if (strcmp(otherName, operatorName) == 0 &&
647 otherNamespace == operatorNamespace &&
648 otherLeftTypeId == leftTypeId &&
649 otherRightTypeId == rightTypeId)
650 {
651 /* self-linkage to new operator; caller must handle this */
652 return InvalidOid;
653 }
654
655 /* not in catalogs, different from operator, so make shell */
656
657 aclresult = object_aclcheck(NamespaceRelationId, otherNamespace, GetUserId(),
658 ACL_CREATE);
659 if (aclresult != ACLCHECK_OK)
660 aclcheck_error(aclresult, OBJECT_SCHEMA,
661 get_namespace_name(otherNamespace));
662
663 other_oid = OperatorShellMake(otherName,
664 otherNamespace,
665 otherLeftTypeId,
666 otherRightTypeId);
667 return other_oid;
668}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
#define OidIsValid(objectId)
Definition: c.h:732
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid GetUserId(void)
Definition: miscinit.c:517
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
@ OBJECT_SCHEMA
Definition: parsenodes.h:2348
#define ACL_CREATE
Definition: parsenodes.h:85
static Oid OperatorShellMake(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
Definition: pg_operator.c:193
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:164
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, get_namespace_name(), GetUserId(), InvalidOid, object_aclcheck(), OBJECT_SCHEMA, OidIsValid, OperatorLookup(), OperatorShellMake(), and QualifiedNameGetCreationNamespace().

Referenced by OperatorCreate().

◆ makeOperatorDependencies()

ObjectAddress makeOperatorDependencies ( HeapTuple  tuple,
bool  makeExtensionDep,
bool  isUpdate 
)

Definition at line 853 of file pg_operator.c.

856{
858 ObjectAddress myself,
859 referenced;
860 ObjectAddresses *addrs;
861
862 ObjectAddressSet(myself, OperatorRelationId, oper->oid);
863
864 /*
865 * If we are updating the operator, delete any existing entries, except
866 * for extension membership which should remain the same.
867 */
868 if (isUpdate)
869 {
870 deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
872 }
873
874 addrs = new_object_addresses();
875
876 /* Dependency on namespace */
877 if (OidIsValid(oper->oprnamespace))
878 {
879 ObjectAddressSet(referenced, NamespaceRelationId, oper->oprnamespace);
880 add_exact_object_address(&referenced, addrs);
881 }
882
883 /* Dependency on left type */
884 if (OidIsValid(oper->oprleft))
885 {
886 ObjectAddressSet(referenced, TypeRelationId, oper->oprleft);
887 add_exact_object_address(&referenced, addrs);
888 }
889
890 /* Dependency on right type */
891 if (OidIsValid(oper->oprright))
892 {
893 ObjectAddressSet(referenced, TypeRelationId, oper->oprright);
894 add_exact_object_address(&referenced, addrs);
895 }
896
897 /* Dependency on result type */
898 if (OidIsValid(oper->oprresult))
899 {
900 ObjectAddressSet(referenced, TypeRelationId, oper->oprresult);
901 add_exact_object_address(&referenced, addrs);
902 }
903
904 /*
905 * NOTE: we do not consider the operator to depend on the associated
906 * operators oprcom and oprnegate. We do not want to delete this operator
907 * if those go away, but only reset the link fields; which is not a
908 * function that the dependency logic can handle. (It's taken care of
909 * manually within RemoveOperatorById, instead.)
910 */
911
912 /* Dependency on implementation function */
913 if (OidIsValid(oper->oprcode))
914 {
915 ObjectAddressSet(referenced, ProcedureRelationId, oper->oprcode);
916 add_exact_object_address(&referenced, addrs);
917 }
918
919 /* Dependency on restriction selectivity function */
920 if (OidIsValid(oper->oprrest))
921 {
922 ObjectAddressSet(referenced, ProcedureRelationId, oper->oprrest);
923 add_exact_object_address(&referenced, addrs);
924 }
925
926 /* Dependency on join selectivity function */
927 if (OidIsValid(oper->oprjoin))
928 {
929 ObjectAddressSet(referenced, ProcedureRelationId, oper->oprjoin);
930 add_exact_object_address(&referenced, addrs);
931 }
932
935
936 /* Dependency on owner */
937 recordDependencyOnOwner(OperatorRelationId, oper->oid,
938 oper->oprowner);
939
940 /* Dependency on extension */
941 if (makeExtensionDep)
942 recordDependencyOnCurrentExtension(&myself, isUpdate);
943
944 return myself;
945}
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2757
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2548
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2788
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:370
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:301
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1047
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168

References add_exact_object_address(), ObjectAddress::classId, deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_NORMAL, free_object_addresses(), GETSTRUCT, new_object_addresses(), ObjectAddressSet, ObjectAddress::objectId, OidIsValid, oper(), record_object_address_dependencies(), recordDependencyOnCurrentExtension(), and recordDependencyOnOwner().

Referenced by AlterOperator(), OperatorCreate(), and OperatorShellMake().

◆ OperatorCreate()

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 
)

Definition at line 321 of file pg_operator.c.

332{
333 Relation pg_operator_desc;
334 HeapTuple tup;
335 bool isUpdate;
336 bool nulls[Natts_pg_operator];
337 bool replaces[Natts_pg_operator];
338 Datum values[Natts_pg_operator];
339 Oid operatorObjectId;
340 bool operatorAlreadyDefined;
341 Oid operResultType;
342 Oid commutatorId,
343 negatorId;
344 bool selfCommutator = false;
345 NameData oname;
346 int i;
347 ObjectAddress address;
348
349 /*
350 * Sanity checks
351 */
352 if (!validOperatorName(operatorName))
354 (errcode(ERRCODE_INVALID_NAME),
355 errmsg("\"%s\" is not a valid operator name",
356 operatorName)));
357
358 operResultType = get_func_rettype(procedureId);
359
360 OperatorValidateParams(leftTypeId,
361 rightTypeId,
362 operResultType,
363 commutatorName != NIL,
364 negatorName != NIL,
365 OidIsValid(restrictionId),
366 OidIsValid(joinId),
367 canMerge,
368 canHash);
369
370 operatorObjectId = OperatorGet(operatorName,
371 operatorNamespace,
372 leftTypeId,
373 rightTypeId,
374 &operatorAlreadyDefined);
375
376 if (operatorAlreadyDefined)
378 (errcode(ERRCODE_DUPLICATE_FUNCTION),
379 errmsg("operator %s already exists",
380 operatorName)));
381
382 /*
383 * At this point, if operatorObjectId is not InvalidOid then we are
384 * filling in a previously-created shell. Insist that the user own any
385 * such shell.
386 */
387 if (OidIsValid(operatorObjectId) &&
388 !object_ownercheck(OperatorRelationId, operatorObjectId, GetUserId()))
390 operatorName);
391
392 /*
393 * Set up the other operators. If they do not currently exist, create
394 * shells in order to get ObjectId's.
395 */
396
397 if (commutatorName)
398 {
399 /* commutator has reversed arg types */
400 commutatorId = get_other_operator(commutatorName,
401 rightTypeId, leftTypeId,
402 operatorName, operatorNamespace,
403 leftTypeId, rightTypeId);
404
405 /* Permission check: must own other operator */
406 if (OidIsValid(commutatorId) &&
407 !object_ownercheck(OperatorRelationId, commutatorId, GetUserId()))
409 NameListToString(commutatorName));
410
411 /*
412 * If self-linkage to the new operator is requested, we'll fix it
413 * below. (In case of self-linkage to an existing shell operator, we
414 * need do nothing special.)
415 */
416 if (!OidIsValid(commutatorId))
417 selfCommutator = true;
418 }
419 else
420 commutatorId = InvalidOid;
421
422 if (negatorName)
423 {
424 /* negator has same arg types */
425 negatorId = get_other_operator(negatorName,
426 leftTypeId, rightTypeId,
427 operatorName, operatorNamespace,
428 leftTypeId, rightTypeId);
429
430 /* Permission check: must own other operator */
431 if (OidIsValid(negatorId) &&
432 !object_ownercheck(OperatorRelationId, negatorId, GetUserId()))
434 NameListToString(negatorName));
435
436 /*
437 * Prevent self negation, as it doesn't make sense. It's self
438 * negation if result is InvalidOid (negator would be the same
439 * operator but it doesn't exist yet) or operatorObjectId (we are
440 * replacing a shell that would need to be its own negator).
441 */
442 if (!OidIsValid(negatorId) || negatorId == operatorObjectId)
444 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
445 errmsg("operator cannot be its own negator")));
446 }
447 else
448 negatorId = InvalidOid;
449
450 /*
451 * set up values in the operator tuple
452 */
453
454 for (i = 0; i < Natts_pg_operator; ++i)
455 {
456 values[i] = (Datum) NULL;
457 replaces[i] = true;
458 nulls[i] = false;
459 }
460
461 namestrcpy(&oname, operatorName);
462 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
463 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
464 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
465 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
466 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
467 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
468 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
469 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
470 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
471 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
472 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
473 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
474 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
475 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
476
477 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
478
479 /*
480 * If we are replacing an operator shell, update; else insert
481 */
482 if (operatorObjectId)
483 {
484 isUpdate = true;
485
486 tup = SearchSysCacheCopy1(OPEROID,
487 ObjectIdGetDatum(operatorObjectId));
488 if (!HeapTupleIsValid(tup))
489 elog(ERROR, "cache lookup failed for operator %u",
490 operatorObjectId);
491
492 replaces[Anum_pg_operator_oid - 1] = false;
493 tup = heap_modify_tuple(tup,
494 RelationGetDescr(pg_operator_desc),
495 values,
496 nulls,
497 replaces);
498
499 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
500 }
501 else
502 {
503 isUpdate = false;
504
505 operatorObjectId = GetNewOidWithIndex(pg_operator_desc,
506 OperatorOidIndexId,
507 Anum_pg_operator_oid);
508 values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
509
510 tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
511 values, nulls);
512
513 CatalogTupleInsert(pg_operator_desc, tup);
514 }
515
516 /* Add dependencies for the entry */
517 address = makeOperatorDependencies(tup, true, isUpdate);
518
519 /*
520 * If a commutator and/or negator link is provided, update the other
521 * operator(s) to point at this one, if they don't already have a link.
522 * This supports an alternative style of operator definition wherein the
523 * user first defines one operator without giving negator or commutator,
524 * then defines the other operator of the pair with the proper commutator
525 * or negator attribute. That style doesn't require creation of a shell,
526 * and it's the only style that worked right before Postgres version 6.5.
527 * This code also takes care of the situation where the new operator is
528 * its own commutator.
529 */
530 if (selfCommutator)
531 commutatorId = operatorObjectId;
532
533 if (OidIsValid(commutatorId) || OidIsValid(negatorId))
534 OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
535
536 /* Post creation hook for new operator */
537 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
538
539 table_close(pg_operator_desc, RowExclusiveLock);
540
541 return address;
542}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
static Datum values[MAXATTR]
Definition: bootstrap.c:151
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
int i
Definition: isn.c:72
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
void namestrcpy(Name name, const char *str)
Definition: name.c:233
char * NameListToString(const List *names)
Definition: namespace.c:3594
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
@ OBJECT_OPERATOR
Definition: parsenodes.h:2337
#define NIL
Definition: pg_list.h:68
static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
Definition: pg_operator.c:622
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:124
static bool validOperatorName(const char *name)
Definition: pg_operator.c:68
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
Definition: pg_operator.c:556
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
Definition: pg_operator.c:853
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:684
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:698
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References aclcheck_error(), ACLCHECK_NOT_OWNER, BoolGetDatum(), CatalogTupleInsert(), CatalogTupleUpdate(), CharGetDatum(), elog, ereport, errcode(), errmsg(), ERROR, get_func_rettype(), get_other_operator(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostCreateHook, makeOperatorDependencies(), NameGetDatum(), NameListToString(), namestrcpy(), NIL, OBJECT_OPERATOR, object_ownercheck(), ObjectIdGetDatum(), OidIsValid, OperatorGet(), OperatorUpd(), OperatorValidateParams(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), validOperatorName(), and values.

Referenced by DefineOperator().

◆ OperatorGet()

static Oid OperatorGet ( const char *  operatorName,
Oid  operatorNamespace,
Oid  leftObjectId,
Oid  rightObjectId,
bool *  defined 
)
static

Definition at line 124 of file pg_operator.c.

129{
130 HeapTuple tup;
131 Oid operatorObjectId;
132
133 tup = SearchSysCache4(OPERNAMENSP,
134 PointerGetDatum(operatorName),
135 ObjectIdGetDatum(leftObjectId),
136 ObjectIdGetDatum(rightObjectId),
137 ObjectIdGetDatum(operatorNamespace));
138 if (HeapTupleIsValid(tup))
139 {
141
142 operatorObjectId = oprform->oid;
143 *defined = RegProcedureIsValid(oprform->oprcode);
144 ReleaseSysCache(tup);
145 }
146 else
147 {
148 operatorObjectId = InvalidOid;
149 *defined = false;
150 }
151
152 return operatorObjectId;
153}
#define RegProcedureIsValid(p)
Definition: c.h:734
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:254

References GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), PointerGetDatum(), RegProcedureIsValid, ReleaseSysCache(), and SearchSysCache4().

Referenced by OperatorCreate().

◆ OperatorLookup()

Oid OperatorLookup ( List operatorName,
Oid  leftObjectId,
Oid  rightObjectId,
bool *  defined 
)

Definition at line 164 of file pg_operator.c.

168{
169 Oid operatorObjectId;
170 RegProcedure oprcode;
171
172 operatorObjectId = LookupOperName(NULL, operatorName,
173 leftObjectId, rightObjectId,
174 true, -1);
175 if (!OidIsValid(operatorObjectId))
176 {
177 *defined = false;
178 return InvalidOid;
179 }
180
181 oprcode = get_opcode(operatorObjectId);
182 *defined = RegProcedureIsValid(oprcode);
183
184 return operatorObjectId;
185}
regproc RegProcedure
Definition: c.h:607
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1285
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:99

References get_opcode(), InvalidOid, LookupOperName(), OidIsValid, and RegProcedureIsValid.

Referenced by get_other_operator(), and ValidateOperatorReference().

◆ OperatorShellMake()

static Oid OperatorShellMake ( const char *  operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 193 of file pg_operator.c.

197{
198 Relation pg_operator_desc;
199 Oid operatorObjectId;
200 int i;
201 HeapTuple tup;
202 Datum values[Natts_pg_operator];
203 bool nulls[Natts_pg_operator];
204 NameData oname;
205 TupleDesc tupDesc;
206
207 /*
208 * validate operator name
209 */
210 if (!validOperatorName(operatorName))
212 (errcode(ERRCODE_INVALID_NAME),
213 errmsg("\"%s\" is not a valid operator name",
214 operatorName)));
215
216 /*
217 * open pg_operator
218 */
219 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
220 tupDesc = pg_operator_desc->rd_att;
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 operatorObjectId = GetNewOidWithIndex(pg_operator_desc, OperatorOidIndexId,
236 Anum_pg_operator_oid);
237 values[Anum_pg_operator_oid - 1] = ObjectIdGetDatum(operatorObjectId);
238 namestrcpy(&oname, operatorName);
239 values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
240 values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
241 values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
242 values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? 'b' : 'l');
243 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
244 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
245 values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
246 values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
247 values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
248 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
249 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
250 values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
251 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
252 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
253
254 /*
255 * create a new operator tuple
256 */
257 tup = heap_form_tuple(tupDesc, values, nulls);
258
259 /*
260 * insert our "shell" operator tuple
261 */
262 CatalogTupleInsert(pg_operator_desc, tup);
263
264 /* Add dependencies for the entry */
265 makeOperatorDependencies(tup, true, false);
266
267 heap_freetuple(tup);
268
269 /* Post creation hook for new shell operator */
270 InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
271
272 /*
273 * Make sure the tuple is visible for subsequent lookups/updates.
274 */
276
277 /*
278 * close the operator relation and return the oid.
279 */
280 table_close(pg_operator_desc, RowExclusiveLock);
281
282 return operatorObjectId;
283}
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
TupleDesc rd_att
Definition: rel.h:112
void CommandCounterIncrement(void)
Definition: xact.c:1099

References BoolGetDatum(), CatalogTupleInsert(), CharGetDatum(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), i, InvalidOid, InvokeObjectPostCreateHook, makeOperatorDependencies(), NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), RelationData::rd_att, RowExclusiveLock, table_close(), table_open(), validOperatorName(), and values.

Referenced by get_other_operator().

◆ OperatorUpd()

void OperatorUpd ( Oid  baseId,
Oid  commId,
Oid  negId,
bool  isDelete 
)

Definition at line 684 of file pg_operator.c.

685{
686 Relation pg_operator_desc;
687 HeapTuple tup;
688
689 /*
690 * If we're making an operator into its own commutator, then we need a
691 * command-counter increment here, since we've just inserted the tuple
692 * we're about to update. But when we're dropping an operator, we can
693 * skip this because we're at the beginning of the command.
694 */
695 if (!isDelete)
697
698 /* Open the relation. */
699 pg_operator_desc = table_open(OperatorRelationId, RowExclusiveLock);
700
701 /* Get a writable copy of the commutator's tuple. */
702 if (OidIsValid(commId))
703 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
704 else
705 tup = NULL;
706
707 /* Update the commutator's tuple if need be. */
708 if (HeapTupleIsValid(tup))
709 {
711 bool update_commutator = false;
712
713 /*
714 * We can skip doing anything if the commutator's oprcom field is
715 * already what we want. While that's not expected in the isDelete
716 * case, it's perfectly possible when filling in a shell operator.
717 */
718 if (isDelete && OidIsValid(t->oprcom))
719 {
720 t->oprcom = InvalidOid;
721 update_commutator = true;
722 }
723 else if (!isDelete && t->oprcom != baseId)
724 {
725 /*
726 * If commutator's oprcom field is already set to point to some
727 * third operator, it's an error. Changing its link would be
728 * unsafe, and letting the inconsistency stand would not be good
729 * either. This might be indicative of catalog corruption, so
730 * don't assume t->oprcom is necessarily a valid operator.
731 */
732 if (OidIsValid(t->oprcom))
733 {
734 char *thirdop = get_opname(t->oprcom);
735
736 if (thirdop != NULL)
738 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
739 errmsg("commutator operator %s is already the commutator of operator %s",
740 NameStr(t->oprname), thirdop)));
741 else
743 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
744 errmsg("commutator operator %s is already the commutator of operator %u",
745 NameStr(t->oprname), t->oprcom)));
746 }
747
748 t->oprcom = baseId;
749 update_commutator = true;
750 }
751
752 /* If any columns were found to need modification, update tuple. */
753 if (update_commutator)
754 {
755 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
756
757 /*
758 * Do CCI to make the updated tuple visible. We must do this in
759 * case the commutator is also the negator. (Which would be a
760 * logic error on the operator definer's part, but that's not a
761 * good reason to fail here.) We would need a CCI anyway in the
762 * deletion case for a self-commutator with no negator.
763 */
765 }
766 }
767
768 /*
769 * Similarly find and update the negator, if any.
770 */
771 if (OidIsValid(negId))
772 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
773 else
774 tup = NULL;
775
776 if (HeapTupleIsValid(tup))
777 {
779 bool update_negator = false;
780
781 /*
782 * We can skip doing anything if the negator's oprnegate field is
783 * already what we want. While that's not expected in the isDelete
784 * case, it's perfectly possible when filling in a shell operator.
785 */
786 if (isDelete && OidIsValid(t->oprnegate))
787 {
788 t->oprnegate = InvalidOid;
789 update_negator = true;
790 }
791 else if (!isDelete && t->oprnegate != baseId)
792 {
793 /*
794 * If negator's oprnegate field is already set to point to some
795 * third operator, it's an error. Changing its link would be
796 * unsafe, and letting the inconsistency stand would not be good
797 * either. This might be indicative of catalog corruption, so
798 * don't assume t->oprnegate is necessarily a valid operator.
799 */
800 if (OidIsValid(t->oprnegate))
801 {
802 char *thirdop = get_opname(t->oprnegate);
803
804 if (thirdop != NULL)
806 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
807 errmsg("negator operator %s is already the negator of operator %s",
808 NameStr(t->oprname), thirdop)));
809 else
811 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
812 errmsg("negator operator %s is already the negator of operator %u",
813 NameStr(t->oprname), t->oprnegate)));
814 }
815
816 t->oprnegate = baseId;
817 update_negator = true;
818 }
819
820 /* If any columns were found to need modification, update tuple. */
821 if (update_negator)
822 {
823 CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
824
825 /*
826 * In the deletion case, do CCI to make the updated tuple visible.
827 * We must do this in case the operator is its own negator. (Which
828 * would be a logic error on the operator definer's part, but
829 * that's not a good reason to fail here.)
830 */
831 if (isDelete)
833 }
834 }
835
836 /* Close relation and release catalog lock. */
837 table_close(pg_operator_desc, RowExclusiveLock);
838}
#define NameStr(name)
Definition: c.h:703
char * get_opname(Oid opno)
Definition: lsyscache.c:1310

References CatalogTupleUpdate(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, get_opname(), GETSTRUCT, HeapTupleIsValid, InvalidOid, NameStr, ObjectIdGetDatum(), OidIsValid, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), and table_open().

Referenced by AlterOperator(), OperatorCreate(), and RemoveOperatorById().

◆ OperatorValidateParams()

void OperatorValidateParams ( Oid  leftTypeId,
Oid  rightTypeId,
Oid  operResultType,
bool  hasCommutator,
bool  hasNegator,
bool  hasRestrictionSelectivity,
bool  hasJoinSelectivity,
bool  canMerge,
bool  canHash 
)

Definition at line 556 of file pg_operator.c.

565{
566 if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
567 {
568 /* If it's not a binary op, these things mustn't be set: */
569 if (hasCommutator)
571 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572 errmsg("only binary operators can have commutators")));
573 if (hasJoinSelectivity)
575 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
576 errmsg("only binary operators can have join selectivity")));
577 if (canMerge)
579 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
580 errmsg("only binary operators can merge join")));
581 if (canHash)
583 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
584 errmsg("only binary operators can hash")));
585 }
586
587 if (operResultType != BOOLOID)
588 {
589 /* If it's not a boolean op, these things mustn't be set: */
590 if (hasNegator)
592 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593 errmsg("only boolean operators can have negators")));
594 if (hasRestrictionSelectivity)
596 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
597 errmsg("only boolean operators can have restriction selectivity")));
598 if (hasJoinSelectivity)
600 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601 errmsg("only boolean operators can have join selectivity")));
602 if (canMerge)
604 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
605 errmsg("only boolean operators can merge join")));
606 if (canHash)
608 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
609 errmsg("only boolean operators can hash")));
610 }
611}

References ereport, errcode(), errmsg(), ERROR, and OidIsValid.

Referenced by AlterOperator(), and OperatorCreate().

◆ validOperatorName()

static bool validOperatorName ( const char *  name)
static

Definition at line 68 of file pg_operator.c.

69{
70 size_t len = strlen(name);
71
72 /* Can't be empty or too long */
73 if (len == 0 || len >= NAMEDATALEN)
74 return false;
75
76 /* Can't contain any invalid characters */
77 /* Test string here should match op_chars in scan.l */
78 if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
79 return false;
80
81 /* Can't contain slash-star or dash-dash (comment starts) */
82 if (strstr(name, "/*") || strstr(name, "--"))
83 return false;
84
85 /*
86 * For SQL standard compatibility, '+' and '-' cannot be the last char of
87 * a multi-char operator unless the operator contains chars that are not
88 * in SQL operators. The idea is to lex '=-' as two operators, but not to
89 * forbid operator names like '?-' that could not be sequences of standard
90 * SQL operators.
91 */
92 if (len > 1 &&
93 (name[len - 1] == '+' ||
94 name[len - 1] == '-'))
95 {
96 int ic;
97
98 for (ic = len - 2; ic >= 0; ic--)
99 {
100 if (strchr("~!@#^&|`?%", name[ic]))
101 break;
102 }
103 if (ic < 0)
104 return false; /* nope, not valid */
105 }
106
107 /* != isn't valid either, because parser will convert it to <> */
108 if (strcmp(name, "!=") == 0)
109 return false;
110
111 return true;
112}
#define NAMEDATALEN
const void size_t len
const char * name

References len, name, and NAMEDATALEN.

Referenced by OperatorCreate(), and OperatorShellMake().