PostgreSQL Source Code  git master
pg_operator.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.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 OperatorLookup (List *operatorName, 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, bool isCommutator)
 
static bool validOperatorName (const char *name)
 
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 OperatorUpd (Oid baseId, Oid commId, Oid negId, bool isDelete)
 
ObjectAddress makeOperatorDependencies (HeapTuple tuple, 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,
bool  isCommutator 
)
static

Definition at line 575 of file pg_operator.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), GetUserId(), InvalidOid, OBJECT_SCHEMA, OidIsValid, OperatorLookup(), OperatorShellMake(), pg_namespace_aclcheck(), and QualifiedNameGetCreationNamespace().

Referenced by OperatorCreate().

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 }
Oid GetUserId(void)
Definition: miscinit.c:379
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2975
static Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:169
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
static Oid OperatorShellMake(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId)
Definition: pg_operator.c:198
#define OidIsValid(objectId)
Definition: c.h:605
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4689
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3051
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:178
#define InvalidOid
Definition: postgres_ext.h:36
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ makeOperatorDependencies()

ObjectAddress makeOperatorDependencies ( HeapTuple  tuple,
bool  isUpdate 
)

Definition at line 763 of file pg_operator.c.

References ObjectAddress::classId, deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_NORMAL, GETSTRUCT, HeapTupleGetOid, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, oper(), recordDependencyOn(), recordDependencyOnCurrentExtension(), and recordDependencyOnOwner().

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

764 {
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);
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 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
Definition: pg_depend.c:191
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:159
#define OidIsValid(objectId)
Definition: c.h:605
void deleteSharedDependencyRecordsFor(Oid classId, Oid objectId, int32 objectSubId)
Definition: pg_shdepend.c:823
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:139
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:82
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:377

◆ 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 323 of file pg_operator.c.

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

Referenced by DefineOperator().

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()))
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()))
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()))
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 
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 }
#define NameGetDatum(X)
Definition: postgres.h:580
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define RelationGetDescr(relation)
Definition: rel.h:433
Oid GetUserId(void)
Definition: miscinit.c:379
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:763
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:129
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4803
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define OidIsValid(objectId)
Definition: c.h:605
static Oid get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId, const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, bool isCommutator)
Definition: pg_operator.c:575
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1444
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3349
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:570
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
char * NameListToString(List *names)
Definition: namespace.c:3082
uintptr_t Datum
Definition: postgres.h:367
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define BoolGetDatum(X)
Definition: postgres.h:387
#define InvalidOid
Definition: postgres_ext.h:36
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:644
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
#define CharGetDatum(X)
Definition: postgres.h:401
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define elog
Definition: elog.h:219
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1173
static bool validOperatorName(const char *name)
Definition: pg_operator.c:73

◆ OperatorGet()

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

Definition at line 129 of file pg_operator.c.

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

Referenced by OperatorCreate().

134 {
135  HeapTuple tup;
136  Oid operatorObjectId;
137 
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 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define PointerGetDatum(X)
Definition: postgres.h:541
regproc RegProcedure
Definition: c.h:472
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define RegProcedureIsValid(p)
Definition: c.h:607
HeapTuple SearchSysCache4(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4)
Definition: syscache.c:1145
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:82
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:707

◆ OperatorLookup()

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

Definition at line 169 of file pg_operator.c.

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

Referenced by get_other_operator().

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 }
regproc RegProcedure
Definition: c.h:472
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:102
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:605
#define RegProcedureIsValid(p)
Definition: c.h:607
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1079

◆ OperatorShellMake()

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

Definition at line 198 of file pg_operator.c.

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

Referenced by get_other_operator().

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  */
278 
279  /*
280  * close the operator relation and return the oid.
281  */
282  heap_close(pg_operator_desc, RowExclusiveLock);
283 
284  return operatorObjectId;
285 }
#define NameGetDatum(X)
Definition: postgres.h:580
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
Oid GetUserId(void)
Definition: miscinit.c:379
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:763
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1074
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1773
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:163
Definition: c.h:570
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:367
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
TupleDesc rd_att
Definition: rel.h:85
#define BoolGetDatum(X)
Definition: postgres.h:387
#define InvalidOid
Definition: postgres_ext.h:36
#define CharGetDatum(X)
Definition: postgres.h:401
static Datum values[MAXATTR]
Definition: bootstrap.c:164
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
static bool validOperatorName(const char *name)
Definition: pg_operator.c:73

◆ OperatorUpd()

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

Definition at line 644 of file pg_operator.c.

References CatalogTupleUpdate(), CommandCounterIncrement(), GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, OidIsValid, OPEROID, RowExclusiveLock, SearchSysCacheCopy1, and HeapTupleData::t_self.

Referenced by OperatorCreate(), and RemoveOperatorById().

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)
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))
664  else
665  tup = NULL;
666 
667  /* Update the commutator's tuple if need be. */
668  if (HeapTupleIsValid(tup))
669  {
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  */
702  }
703  }
704 
705  /*
706  * Similarly find and update the negator, if any.
707  */
708  if (OidIsValid(negId))
710  else
711  tup = NULL;
712 
713  if (HeapTupleIsValid(tup))
714  {
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)
747  }
748  }
749 
750  /* Close relation and release catalog lock. */
751  heap_close(pg_operator_desc, RowExclusiveLock);
752 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:668
#define heap_close(r, l)
Definition: heapam.h:97
#define OidIsValid(objectId)
Definition: c.h:605
#define ObjectIdGetDatum(X)
Definition: postgres.h:492
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
void CommandCounterIncrement(void)
Definition: xact.c:914
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:211
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:82
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:173

◆ validOperatorName()

static bool validOperatorName ( const char *  name)
static

Definition at line 73 of file pg_operator.c.

References NAMEDATALEN.

Referenced by OperatorCreate(), and OperatorShellMake().

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 }
#define NAMEDATALEN
const char * name
Definition: encode.c:521