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:2702
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3890
#define OidIsValid(objectId)
Definition: c.h:775
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid GetUserId(void)
Definition: miscinit.c:514
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3472
@ OBJECT_SCHEMA
Definition: parsenodes.h:2297
#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:36
unsigned int Oid
Definition: postgres_ext.h:31

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 
934  free_object_addresses(addrs);
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:2740
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2485
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2531
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2771
@ 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:302
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:194
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:1039
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165

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))
353  ereport(ERROR,
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)
377  ereport(ERROR,
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)
443  ereport(ERROR,
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:4144
static Datum values[MAXATTR]
Definition: bootstrap.c:152
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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:1209
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
#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:73
#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:3579
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
@ OBJECT_OPERATOR
Definition: parsenodes.h:2286
#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:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:373
static Datum CharGetDatum(char X)
Definition: postgres.h:122
#define RelationGetDescr(relation)
Definition: rel.h:531
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:741
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
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:777
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:251

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:650
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))
211  ereport(ERROR,
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:1434
TupleDesc rd_att
Definition: rel.h:112
void CommandCounterIncrement(void)
Definition: xact.c:1097

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)
737  ereport(ERROR,
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
742  ereport(ERROR,
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)
805  ereport(ERROR,
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
810  ereport(ERROR,
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:746
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)
570  ereport(ERROR,
571  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
572  errmsg("only binary operators can have commutators")));
573  if (hasJoinSelectivity)
574  ereport(ERROR,
575  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
576  errmsg("only binary operators can have join selectivity")));
577  if (canMerge)
578  ereport(ERROR,
579  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
580  errmsg("only binary operators can merge join")));
581  if (canHash)
582  ereport(ERROR,
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)
591  ereport(ERROR,
592  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
593  errmsg("only boolean operators can have negators")));
594  if (hasRestrictionSelectivity)
595  ereport(ERROR,
596  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
597  errmsg("only boolean operators can have restriction selectivity")));
598  if (hasJoinSelectivity)
599  ereport(ERROR,
600  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
601  errmsg("only boolean operators can have join selectivity")));
602  if (canMerge)
603  ereport(ERROR,
604  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
605  errmsg("only boolean operators can merge join")));
606  if (canHash)
607  ereport(ERROR,
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().