PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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_operator_fn.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

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

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

Referenced by OperatorCreate().

579 {
580  Oid other_oid;
581  bool otherDefined;
582  char *otherName;
583  Oid otherNamespace;
584  AclResult aclresult;
585 
586  other_oid = OperatorLookup(otherOp,
587  otherLeftTypeId,
588  otherRightTypeId,
589  &otherDefined);
590 
591  if (OidIsValid(other_oid))
592  {
593  /* other op already in catalogs */
594  return other_oid;
595  }
596 
597  otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
598  &otherName);
599 
600  if (strcmp(otherName, operatorName) == 0 &&
601  otherNamespace == operatorNamespace &&
602  otherLeftTypeId == leftTypeId &&
603  otherRightTypeId == rightTypeId)
604  {
605  /*
606  * self-linkage to this operator; caller will fix later. Note that
607  * only self-linkage for commutation makes sense.
608  */
609  if (!isCommutator)
610  ereport(ERROR,
611  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
612  errmsg("operator cannot be its own negator or sort operator")));
613  return InvalidOid;
614  }
615 
616  /* not in catalogs, different from operator, so make shell */
617 
618  aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
619  ACL_CREATE);
620  if (aclresult != ACLCHECK_OK)
622  get_namespace_name(otherNamespace));
623 
624  other_oid = OperatorShellMake(otherName,
625  otherNamespace,
626  otherLeftTypeId,
627  otherRightTypeId);
628  return other_oid;
629 }
Oid GetUserId(void)
Definition: miscinit.c:284
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2956
static Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:170
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:199
#define OidIsValid(objectId)
Definition: c.h:538
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3033
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define ereport(elevel, rest)
Definition: elog.h:122
AclResult
Definition: acl.h:170
#define InvalidOid
Definition: postgres_ext.h:36
int errmsg(const char *fmt,...)
Definition: elog.c:797
ObjectAddress makeOperatorDependencies ( HeapTuple  tuple,
bool  isUpdate 
)

Definition at line 764 of file pg_operator.c.

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

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

765 {
767  ObjectAddress myself,
768  referenced;
769 
770  myself.classId = OperatorRelationId;
771  myself.objectId = HeapTupleGetOid(tuple);
772  myself.objectSubId = 0;
773 
774  /*
775  * If we are updating the operator, delete any existing entries, except
776  * for extension membership which should remain the same.
777  */
778  if (isUpdate)
779  {
780  deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
782  }
783 
784  /* Dependency on namespace */
785  if (OidIsValid(oper->oprnamespace))
786  {
787  referenced.classId = NamespaceRelationId;
788  referenced.objectId = oper->oprnamespace;
789  referenced.objectSubId = 0;
790  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
791  }
792 
793  /* Dependency on left type */
794  if (OidIsValid(oper->oprleft))
795  {
796  referenced.classId = TypeRelationId;
797  referenced.objectId = oper->oprleft;
798  referenced.objectSubId = 0;
799  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
800  }
801 
802  /* Dependency on right type */
803  if (OidIsValid(oper->oprright))
804  {
805  referenced.classId = TypeRelationId;
806  referenced.objectId = oper->oprright;
807  referenced.objectSubId = 0;
808  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
809  }
810 
811  /* Dependency on result type */
812  if (OidIsValid(oper->oprresult))
813  {
814  referenced.classId = TypeRelationId;
815  referenced.objectId = oper->oprresult;
816  referenced.objectSubId = 0;
817  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
818  }
819 
820  /*
821  * NOTE: we do not consider the operator to depend on the associated
822  * operators oprcom and oprnegate. We would not want to delete this
823  * operator if those go away, but only reset the link fields; which is not
824  * a function that the dependency code can presently handle. (Something
825  * could perhaps be done with objectSubId though.) For now, it's okay to
826  * let those links dangle if a referenced operator is removed.
827  */
828 
829  /* Dependency on implementation function */
830  if (OidIsValid(oper->oprcode))
831  {
832  referenced.classId = ProcedureRelationId;
833  referenced.objectId = oper->oprcode;
834  referenced.objectSubId = 0;
835  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
836  }
837 
838  /* Dependency on restriction selectivity function */
839  if (OidIsValid(oper->oprrest))
840  {
841  referenced.classId = ProcedureRelationId;
842  referenced.objectId = oper->oprrest;
843  referenced.objectSubId = 0;
844  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
845  }
846 
847  /* Dependency on join selectivity function */
848  if (OidIsValid(oper->oprjoin))
849  {
850  referenced.classId = ProcedureRelationId;
851  referenced.objectId = oper->oprjoin;
852  referenced.objectSubId = 0;
853  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
854  }
855 
856  /* Dependency on owner */
858  oper->oprowner);
859 
860  /* Dependency on extension */
861  recordDependencyOnCurrentExtension(&myself, true);
862 
863  return myself;
864 }
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define OperatorRelationId
Definition: pg_operator.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define ProcedureRelationId
Definition: pg_proc.h:33
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 TypeRelationId
Definition: pg_type.h:34
#define OidIsValid(objectId)
Definition: c.h:538
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:57
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:377
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 324 of file pg_operator.c.

References ACL_KIND_OPER, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_operator_oprcanhash, Anum_pg_operator_oprcanmerge, Anum_pg_operator_oprcode, Anum_pg_operator_oprcom, Anum_pg_operator_oprjoin, Anum_pg_operator_oprkind, Anum_pg_operator_oprleft, Anum_pg_operator_oprname, Anum_pg_operator_oprnamespace, Anum_pg_operator_oprnegate, Anum_pg_operator_oprowner, Anum_pg_operator_oprrest, Anum_pg_operator_oprresult, Anum_pg_operator_oprright, BoolGetDatum, BOOLOID, 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(), Natts_pg_operator, NULL, ObjectIdGetDatum, OidIsValid, OperatorGet(), OperatorRelationId, OperatorUpd(), OPEROID, pg_oper_ownercheck(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, validOperatorName(), and values.

Referenced by DefineOperator().

335 {
336  Relation pg_operator_desc;
337  HeapTuple tup;
338  bool isUpdate;
339  bool nulls[Natts_pg_operator];
340  bool replaces[Natts_pg_operator];
342  Oid operatorObjectId;
343  bool operatorAlreadyDefined;
344  Oid operResultType;
345  Oid commutatorId,
346  negatorId;
347  bool selfCommutator = false;
348  NameData oname;
349  int i;
350  ObjectAddress address;
351 
352  /*
353  * Sanity checks
354  */
355  if (!validOperatorName(operatorName))
356  ereport(ERROR,
357  (errcode(ERRCODE_INVALID_NAME),
358  errmsg("\"%s\" is not a valid operator name",
359  operatorName)));
360 
361  if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
362  {
363  /* If it's not a binary op, these things mustn't be set: */
364  if (commutatorName)
365  ereport(ERROR,
366  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
367  errmsg("only binary operators can have commutators")));
368  if (OidIsValid(joinId))
369  ereport(ERROR,
370  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
371  errmsg("only binary operators can have join selectivity")));
372  if (canMerge)
373  ereport(ERROR,
374  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
375  errmsg("only binary operators can merge join")));
376  if (canHash)
377  ereport(ERROR,
378  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
379  errmsg("only binary operators can hash")));
380  }
381 
382  operResultType = get_func_rettype(procedureId);
383 
384  if (operResultType != BOOLOID)
385  {
386  /* If it's not a boolean op, these things mustn't be set: */
387  if (negatorName)
388  ereport(ERROR,
389  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
390  errmsg("only boolean operators can have negators")));
391  if (OidIsValid(restrictionId))
392  ereport(ERROR,
393  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
394  errmsg("only boolean operators can have restriction selectivity")));
395  if (OidIsValid(joinId))
396  ereport(ERROR,
397  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
398  errmsg("only boolean operators can have join selectivity")));
399  if (canMerge)
400  ereport(ERROR,
401  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
402  errmsg("only boolean operators can merge join")));
403  if (canHash)
404  ereport(ERROR,
405  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
406  errmsg("only boolean operators can hash")));
407  }
408 
409  operatorObjectId = OperatorGet(operatorName,
410  operatorNamespace,
411  leftTypeId,
412  rightTypeId,
413  &operatorAlreadyDefined);
414 
415  if (operatorAlreadyDefined)
416  ereport(ERROR,
417  (errcode(ERRCODE_DUPLICATE_FUNCTION),
418  errmsg("operator %s already exists",
419  operatorName)));
420 
421  /*
422  * At this point, if operatorObjectId is not InvalidOid then we are
423  * filling in a previously-created shell. Insist that the user own any
424  * such shell.
425  */
426  if (OidIsValid(operatorObjectId) &&
427  !pg_oper_ownercheck(operatorObjectId, GetUserId()))
429  operatorName);
430 
431  /*
432  * Set up the other operators. If they do not currently exist, create
433  * shells in order to get ObjectId's.
434  */
435 
436  if (commutatorName)
437  {
438  /* commutator has reversed arg types */
439  commutatorId = get_other_operator(commutatorName,
440  rightTypeId, leftTypeId,
441  operatorName, operatorNamespace,
442  leftTypeId, rightTypeId,
443  true);
444 
445  /* Permission check: must own other operator */
446  if (OidIsValid(commutatorId) &&
447  !pg_oper_ownercheck(commutatorId, GetUserId()))
449  NameListToString(commutatorName));
450 
451  /*
452  * self-linkage to this operator; will fix below. Note that only
453  * self-linkage for commutation makes sense.
454  */
455  if (!OidIsValid(commutatorId))
456  selfCommutator = true;
457  }
458  else
459  commutatorId = InvalidOid;
460 
461  if (negatorName)
462  {
463  /* negator has same arg types */
464  negatorId = get_other_operator(negatorName,
465  leftTypeId, rightTypeId,
466  operatorName, operatorNamespace,
467  leftTypeId, rightTypeId,
468  false);
469 
470  /* Permission check: must own other operator */
471  if (OidIsValid(negatorId) &&
472  !pg_oper_ownercheck(negatorId, GetUserId()))
474  NameListToString(negatorName));
475  }
476  else
477  negatorId = InvalidOid;
478 
479  /*
480  * set up values in the operator tuple
481  */
482 
483  for (i = 0; i < Natts_pg_operator; ++i)
484  {
485  values[i] = (Datum) NULL;
486  replaces[i] = true;
487  nulls[i] = false;
488  }
489 
490  namestrcpy(&oname, operatorName);
491  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
492  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
494  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
495  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
496  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
497  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
498  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
499  values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
500  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
501  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
502  values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
503  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
504  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
505 
506  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
507 
508  /*
509  * If we are replacing an operator shell, update; else insert
510  */
511  if (operatorObjectId)
512  {
513  isUpdate = true;
514 
516  ObjectIdGetDatum(operatorObjectId));
517  if (!HeapTupleIsValid(tup))
518  elog(ERROR, "cache lookup failed for operator %u",
519  operatorObjectId);
520 
521  tup = heap_modify_tuple(tup,
522  RelationGetDescr(pg_operator_desc),
523  values,
524  nulls,
525  replaces);
526 
527  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
528  }
529  else
530  {
531  isUpdate = false;
532 
533  tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
534  values, nulls);
535 
536  operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
537  }
538 
539  /* Add dependencies for the entry */
540  address = makeOperatorDependencies(tup, isUpdate);
541 
542  /* Post creation hook for new operator */
543  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
544 
545  heap_close(pg_operator_desc, RowExclusiveLock);
546 
547  /*
548  * If a commutator and/or negator link is provided, update the other
549  * operator(s) to point at this one, if they don't already have a link.
550  * This supports an alternative style of operator definition wherein the
551  * user first defines one operator without giving negator or commutator,
552  * then defines the other operator of the pair with the proper commutator
553  * or negator attribute. That style doesn't require creation of a shell,
554  * and it's the only style that worked right before Postgres version 6.5.
555  * This code also takes care of the situation where the new operator is
556  * its own commutator.
557  */
558  if (selfCommutator)
559  commutatorId = operatorObjectId;
560 
561  if (OidIsValid(commutatorId) || OidIsValid(negatorId))
562  OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
563 
564  return address;
565 }
#define NameGetDatum(X)
Definition: postgres.h:601
#define Anum_pg_operator_oprowner
Definition: pg_operator.h:67
#define Anum_pg_operator_oprleft
Definition: pg_operator.h:71
#define OperatorRelationId
Definition: pg_operator.h:32
#define Anum_pg_operator_oprcanhash
Definition: pg_operator.h:70
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define RelationGetDescr(relation)
Definition: rel.h:428
Oid GetUserId(void)
Definition: miscinit.c:284
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:764
static Oid OperatorGet(const char *operatorName, Oid operatorNamespace, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:130
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4598
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#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:538
#define Anum_pg_operator_oprjoin
Definition: pg_operator.h:78
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:576
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1459
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
ItemPointerData t_self
Definition: htup.h:65
Definition: c.h:493
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Anum_pg_operator_oprnegate
Definition: pg_operator.h:75
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_operator_oprright
Definition: pg_operator.h:72
#define Anum_pg_operator_oprrest
Definition: pg_operator.h:77
char * NameListToString(List *names)
Definition: namespace.c:3063
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:645
#define Anum_pg_operator_oprname
Definition: pg_operator.h:65
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Anum_pg_operator_oprcom
Definition: pg_operator.h:74
#define NULL
Definition: c.h:229
#define Anum_pg_operator_oprresult
Definition: pg_operator.h:73
#define Anum_pg_operator_oprcode
Definition: pg_operator.h:76
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define BOOLOID
Definition: pg_type.h:288
#define CharGetDatum(X)
Definition: postgres.h:422
#define Anum_pg_operator_oprcanmerge
Definition: pg_operator.h:69
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define Anum_pg_operator_oprnamespace
Definition: pg_operator.h:66
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
#define Natts_pg_operator
Definition: pg_operator.h:64
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:794
static bool validOperatorName(const char *name)
Definition: pg_operator.c:74
#define Anum_pg_operator_oprkind
Definition: pg_operator.h:68
static Oid OperatorGet ( const char *  operatorName,
Oid  operatorNamespace,
Oid  leftObjectId,
Oid  rightObjectId,
bool defined 
)
static

Definition at line 130 of file pg_operator.c.

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

Referenced by OperatorCreate().

135 {
136  HeapTuple tup;
137  Oid operatorObjectId;
138 
140  PointerGetDatum(operatorName),
141  ObjectIdGetDatum(leftObjectId),
142  ObjectIdGetDatum(rightObjectId),
143  ObjectIdGetDatum(operatorNamespace));
144  if (HeapTupleIsValid(tup))
145  {
146  RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
147 
148  operatorObjectId = HeapTupleGetOid(tup);
149  *defined = RegProcedureIsValid(oprcode);
150  ReleaseSysCache(tup);
151  }
152  else
153  {
154  operatorObjectId = InvalidOid;
155  *defined = false;
156  }
157 
158  return operatorObjectId;
159 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define PointerGetDatum(X)
Definition: postgres.h:562
#define SearchSysCache4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:162
regproc RegProcedure
Definition: c.h:395
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define RegProcedureIsValid(p)
Definition: c.h:540
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1117
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FormData_pg_operator* Form_pg_operator
Definition: pg_operator.h:57
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
static Oid OperatorLookup ( List operatorName,
Oid  leftObjectId,
Oid  rightObjectId,
bool defined 
)
static

Definition at line 170 of file pg_operator.c.

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

Referenced by get_other_operator().

174 {
175  Oid operatorObjectId;
176  RegProcedure oprcode;
177 
178  operatorObjectId = LookupOperName(NULL, operatorName,
179  leftObjectId, rightObjectId,
180  true, -1);
181  if (!OidIsValid(operatorObjectId))
182  {
183  *defined = false;
184  return InvalidOid;
185  }
186 
187  oprcode = get_opcode(operatorObjectId);
188  *defined = RegProcedureIsValid(oprcode);
189 
190  return operatorObjectId;
191 }
regproc RegProcedure
Definition: c.h:395
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:538
#define RegProcedureIsValid(p)
Definition: c.h:540
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1094
#define NULL
Definition: c.h:229
static Oid OperatorShellMake ( const char *  operatorName,
Oid  operatorNamespace,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 199 of file pg_operator.c.

References Anum_pg_operator_oprcanhash, Anum_pg_operator_oprcanmerge, Anum_pg_operator_oprcode, Anum_pg_operator_oprcom, Anum_pg_operator_oprjoin, Anum_pg_operator_oprkind, Anum_pg_operator_oprleft, Anum_pg_operator_oprname, Anum_pg_operator_oprnamespace, Anum_pg_operator_oprnegate, Anum_pg_operator_oprowner, Anum_pg_operator_oprrest, Anum_pg_operator_oprresult, Anum_pg_operator_oprright, BoolGetDatum, CatalogTupleInsert(), CharGetDatum, CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), i, InvalidOid, InvokeObjectPostCreateHook, makeOperatorDependencies(), NameGetDatum, namestrcpy(), Natts_pg_operator, NULL, ObjectIdGetDatum, OperatorRelationId, RelationData::rd_att, RowExclusiveLock, validOperatorName(), and values.

Referenced by get_other_operator().

203 {
204  Relation pg_operator_desc;
205  Oid operatorObjectId;
206  int i;
207  HeapTuple tup;
209  bool nulls[Natts_pg_operator];
210  NameData oname;
211  TupleDesc tupDesc;
212 
213  /*
214  * validate operator name
215  */
216  if (!validOperatorName(operatorName))
217  ereport(ERROR,
218  (errcode(ERRCODE_INVALID_NAME),
219  errmsg("\"%s\" is not a valid operator name",
220  operatorName)));
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  namestrcpy(&oname, operatorName);
236  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
237  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
239  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
240  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
241  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
242  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
243  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
250 
251  /*
252  * open pg_operator
253  */
254  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
255  tupDesc = pg_operator_desc->rd_att;
256 
257  /*
258  * create a new operator tuple
259  */
260  tup = heap_form_tuple(tupDesc, values, nulls);
261 
262  /*
263  * insert our "shell" operator tuple
264  */
265  operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
266 
267  /* Add dependencies for the entry */
268  makeOperatorDependencies(tup, false);
269 
270  heap_freetuple(tup);
271 
272  /* Post creation hook for new shell operator */
273  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
274 
275  /*
276  * Make sure the tuple is visible for subsequent lookups/updates.
277  */
279 
280  /*
281  * close the operator relation and return the oid.
282  */
283  heap_close(pg_operator_desc, RowExclusiveLock);
284 
285  return operatorObjectId;
286 }
#define NameGetDatum(X)
Definition: postgres.h:601
#define Anum_pg_operator_oprowner
Definition: pg_operator.h:67
#define Anum_pg_operator_oprleft
Definition: pg_operator.h:71
#define OperatorRelationId
Definition: pg_operator.h:32
#define Anum_pg_operator_oprcanhash
Definition: pg_operator.h:70
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
Oid GetUserId(void)
Definition: miscinit.c:284
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
Definition: pg_operator.c:764
int errcode(int sqlerrcode)
Definition: elog.c:575
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#define heap_close(r, l)
Definition: heapam.h:97
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:216
#define Anum_pg_operator_oprjoin
Definition: pg_operator.h:78
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
Definition: c.h:493
#define RowExclusiveLock
Definition: lockdefs.h:38
#define Anum_pg_operator_oprnegate
Definition: pg_operator.h:75
#define ereport(elevel, rest)
Definition: elog.h:122
#define Anum_pg_operator_oprright
Definition: pg_operator.h:72
#define Anum_pg_operator_oprrest
Definition: pg_operator.h:77
uintptr_t Datum
Definition: postgres.h:372
void CommandCounterIncrement(void)
Definition: xact.c:922
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
#define Anum_pg_operator_oprname
Definition: pg_operator.h:65
#define Anum_pg_operator_oprcom
Definition: pg_operator.h:74
#define NULL
Definition: c.h:229
#define Anum_pg_operator_oprresult
Definition: pg_operator.h:73
#define Anum_pg_operator_oprcode
Definition: pg_operator.h:76
#define CharGetDatum(X)
Definition: postgres.h:422
#define Anum_pg_operator_oprcanmerge
Definition: pg_operator.h:69
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define Anum_pg_operator_oprnamespace
Definition: pg_operator.h:66
#define Natts_pg_operator
Definition: pg_operator.h:64
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
static bool validOperatorName(const char *name)
Definition: pg_operator.c:74
#define Anum_pg_operator_oprkind
Definition: pg_operator.h:68
void OperatorUpd ( Oid  baseId,
Oid  commId,
Oid  negId,
bool  isDelete 
)

Definition at line 645 of file pg_operator.c.

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

Referenced by OperatorCreate(), and RemoveOperatorById().

646 {
647  Relation pg_operator_desc;
648  HeapTuple tup;
649 
650  /*
651  * If we're making an operator into its own commutator, then we need a
652  * command-counter increment here, since we've just inserted the tuple
653  * we're about to update. But when we're dropping an operator, we can
654  * skip this because we're at the beginning of the command.
655  */
656  if (!isDelete)
658 
659  /* Open the relation. */
660  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
661 
662  /* Get a writable copy of the commutator's tuple. */
663  if (OidIsValid(commId))
665  else
666  tup = NULL;
667 
668  /* Update the commutator's tuple if need be. */
669  if (HeapTupleIsValid(tup))
670  {
672  bool update_commutator = false;
673 
674  /*
675  * Out of due caution, we only change the commutator's oprcom field if
676  * it has the exact value we expected: InvalidOid when creating an
677  * operator, or baseId when dropping one.
678  */
679  if (isDelete && t->oprcom == baseId)
680  {
681  t->oprcom = InvalidOid;
682  update_commutator = true;
683  }
684  else if (!isDelete && !OidIsValid(t->oprcom))
685  {
686  t->oprcom = baseId;
687  update_commutator = true;
688  }
689 
690  /* If any columns were found to need modification, update tuple. */
691  if (update_commutator)
692  {
693  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
694 
695  /*
696  * Do CCI to make the updated tuple visible. We must do this in
697  * case the commutator is also the negator. (Which would be a
698  * logic error on the operator definer's part, but that's not a
699  * good reason to fail here.) We would need a CCI anyway in the
700  * deletion case for a self-commutator with no negator.
701  */
703  }
704  }
705 
706  /*
707  * Similarly find and update the negator, if any.
708  */
709  if (OidIsValid(negId))
711  else
712  tup = NULL;
713 
714  if (HeapTupleIsValid(tup))
715  {
717  bool update_negator = false;
718 
719  /*
720  * Out of due caution, we only change the negator's oprnegate field if
721  * it has the exact value we expected: InvalidOid when creating an
722  * operator, or baseId when dropping one.
723  */
724  if (isDelete && t->oprnegate == baseId)
725  {
726  t->oprnegate = InvalidOid;
727  update_negator = true;
728  }
729  else if (!isDelete && !OidIsValid(t->oprnegate))
730  {
731  t->oprnegate = baseId;
732  update_negator = true;
733  }
734 
735  /* If any columns were found to need modification, update tuple. */
736  if (update_negator)
737  {
738  CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
739 
740  /*
741  * In the deletion case, do CCI to make the updated tuple visible.
742  * We must do this in case the operator is its own negator. (Which
743  * would be a logic error on the operator definer's part, but
744  * that's not a good reason to fail here.)
745  */
746  if (isDelete)
748  }
749  }
750 
751  /* Close relation and release catalog lock. */
752  heap_close(pg_operator_desc, RowExclusiveLock);
753 }
#define OperatorRelationId
Definition: pg_operator.h:32
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define heap_close(r, l)
Definition: heapam.h:97
#define OidIsValid(objectId)
Definition: c.h:538
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
void CommandCounterIncrement(void)
Definition: xact.c:922
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
FormData_pg_operator* Form_pg_operator
Definition: pg_operator.h:57
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:165
static bool validOperatorName ( const char *  name)
static

Definition at line 74 of file pg_operator.c.

References NAMEDATALEN.

Referenced by OperatorCreate(), and OperatorShellMake().

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