PostgreSQL Source Code  git master
opclasscmds.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/genam.h"
#include "access/hash.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/opfam_internal.h"
#include "catalog/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for opclasscmds.c:

Go to the source code of this file.

Functions

static void AlterOpFamilyAdd (AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int opclassOptsProcNumber, List *items)
 
static void AlterOpFamilyDrop (AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
 
static void processTypesSpec (List *args, Oid *lefttype, Oid *righttype)
 
static void assignOperTypes (OpFamilyMember *member, Oid amoid, Oid typeoid)
 
static void assignProcTypes (OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
 
static void addFamilyMember (List **list, OpFamilyMember *member, bool isProc)
 
static void storeOperators (List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
 
static void storeProcedures (List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
 
static void dropOperators (List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
 
static void dropProcedures (List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
 
static HeapTuple OpFamilyCacheLookup (Oid amID, List *opfamilyname, bool missing_ok)
 
Oid get_opfamily_oid (Oid amID, List *opfamilyname, bool missing_ok)
 
static HeapTuple OpClassCacheLookup (Oid amID, List *opclassname, bool missing_ok)
 
Oid get_opclass_oid (Oid amID, List *opclassname, bool missing_ok)
 
static ObjectAddress CreateOpFamily (const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
 
ObjectAddress DefineOpClass (CreateOpClassStmt *stmt)
 
ObjectAddress DefineOpFamily (CreateOpFamilyStmt *stmt)
 
Oid AlterOpFamily (AlterOpFamilyStmt *stmt)
 
void RemoveOpFamilyById (Oid opfamilyOid)
 
void RemoveOpClassById (Oid opclassOid)
 
void RemoveAmOpEntryById (Oid entryOid)
 
void RemoveAmProcEntryById (Oid entryOid)
 
void IsThereOpClassInNamespace (const char *opcname, Oid opcmethod, Oid opcnamespace)
 
void IsThereOpFamilyInNamespace (const char *opfname, Oid opfmethod, Oid opfnamespace)
 

Function Documentation

◆ addFamilyMember()

static void addFamilyMember ( List **  list,
OpFamilyMember member,
bool  isProc 
)
static

Definition at line 1327 of file opclasscmds.c.

References ereport, errcode(), errmsg(), ERROR, format_type_be(), lappend(), OpFamilyMember::lefttype, lfirst, OpFamilyMember::number, and OpFamilyMember::righttype.

Referenced by AlterOpFamilyAdd(), AlterOpFamilyDrop(), and DefineOpClass().

1328 {
1329  ListCell *l;
1330 
1331  foreach(l, *list)
1332  {
1333  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1334 
1335  if (old->number == member->number &&
1336  old->lefttype == member->lefttype &&
1337  old->righttype == member->righttype)
1338  {
1339  if (isProc)
1340  ereport(ERROR,
1341  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1342  errmsg("function number %d for (%s,%s) appears more than once",
1343  member->number,
1344  format_type_be(member->lefttype),
1345  format_type_be(member->righttype))));
1346  else
1347  ereport(ERROR,
1348  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1349  errmsg("operator number %d for (%s,%s) appears more than once",
1350  member->number,
1351  format_type_be(member->lefttype),
1352  format_type_be(member->righttype))));
1353  }
1354  }
1355  *list = lappend(*list, member);
1356 }
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:321
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 777 of file opclasscmds.c.

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AMNAME, AlterOpFamilyStmt::amname, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, AlterOpFamilyStmt::isDrop, AlterOpFamilyStmt::items, AlterOpFamilyStmt::opfamilyname, ReleaseSysCache(), SearchSysCache1(), and superuser().

Referenced by ProcessUtilitySlow().

778 {
779  Oid amoid, /* our AM's oid */
780  opfamilyoid; /* oid of opfamily */
781  int maxOpNumber, /* amstrategies value */
782  optsProcNumber, /* amopclassopts value */
783  maxProcNumber; /* amsupport value */
784  HeapTuple tup;
785  Form_pg_am amform;
786  IndexAmRoutine *amroutine;
787 
788  /* Get necessary info about access method */
790  if (!HeapTupleIsValid(tup))
791  ereport(ERROR,
792  (errcode(ERRCODE_UNDEFINED_OBJECT),
793  errmsg("access method \"%s\" does not exist",
794  stmt->amname)));
795 
796  amform = (Form_pg_am) GETSTRUCT(tup);
797  amoid = amform->oid;
798  amroutine = GetIndexAmRoutineByAmId(amoid, false);
799  ReleaseSysCache(tup);
800 
801  maxOpNumber = amroutine->amstrategies;
802  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
803  if (maxOpNumber <= 0)
804  maxOpNumber = SHRT_MAX;
805  maxProcNumber = amroutine->amsupport;
806  optsProcNumber = amroutine->amoptsprocnum;
807 
808  /* XXX Should we make any privilege check against the AM? */
809 
810  /* Look up the opfamily */
811  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
812 
813  /*
814  * Currently, we require superuser privileges to alter an opfamily.
815  *
816  * XXX re-enable NOT_USED code sections below if you remove this test.
817  */
818  if (!superuser())
819  ereport(ERROR,
820  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
821  errmsg("must be superuser to alter an operator family")));
822 
823  /*
824  * ADD and DROP cases need separate code from here on down.
825  */
826  if (stmt->isDrop)
827  AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
828  maxOpNumber, maxProcNumber, stmt->items);
829  else
830  AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
831  maxOpNumber, maxProcNumber, optsProcNumber,
832  stmt->items);
833 
834  return opfamilyoid;
835 }
uint16 amsupport
Definition: amapi.h:173
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:967
#define ERROR
Definition: elog.h:43
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
#define CStringGetDatum(X)
Definition: postgres.h:578
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int opclassOptsProcNumber, List *items)
Definition: opclasscmds.c:841
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:142
uint16 amstrategies
Definition: amapi.h:171
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:824
uint16 amoptsprocnum
Definition: amapi.h:175

◆ AlterOpFamilyAdd()

static void AlterOpFamilyAdd ( AlterOpFamilyStmt stmt,
Oid  amoid,
Oid  opfamilyoid,
int  maxOpNumber,
int  maxProcNumber,
int  opclassOptsProcNumber,
List items 
)
static

Definition at line 841 of file opclasscmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, addFamilyMember(), assignOperTypes(), assignProcTypes(), CreateOpClassItem::class_args, elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), get_func_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetUserId(), InvalidOid, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst_node, LookupFuncWithArgs(), LookupOperWithArgs(), member, CreateOpClassItem::name, NIL, OpFamilyMember::number, CreateOpClassItem::number, ObjectWithArgs::objargs, OpFamilyMember::object, OBJECT_FUNCTION, OBJECT_OPERATOR, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, AlterOpFamilyStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), pg_oper_ownercheck(), pg_proc_ownercheck(), processTypesSpec(), OpFamilyMember::righttype, OpFamilyMember::sortfamily, storeOperators(), and storeProcedures().

Referenced by AlterOpFamily().

844 {
845  List *operators; /* OpFamilyMember list for operators */
846  List *procedures; /* OpFamilyMember list for support procs */
847  ListCell *l;
848 
849  operators = NIL;
850  procedures = NIL;
851 
852  /*
853  * Scan the "items" list to obtain additional info.
854  */
855  foreach(l, items)
856  {
858  Oid operOid;
859  Oid funcOid;
860  Oid sortfamilyOid;
862 
863  switch (item->itemtype)
864  {
866  if (item->number <= 0 || item->number > maxOpNumber)
867  ereport(ERROR,
868  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
869  errmsg("invalid operator number %d,"
870  " must be between 1 and %d",
871  item->number, maxOpNumber)));
872  if (item->name->objargs != NIL)
873  operOid = LookupOperWithArgs(item->name, false);
874  else
875  {
876  ereport(ERROR,
877  (errcode(ERRCODE_SYNTAX_ERROR),
878  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
879  operOid = InvalidOid; /* keep compiler quiet */
880  }
881 
882  if (item->order_family)
883  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
884  item->order_family,
885  false);
886  else
887  sortfamilyOid = InvalidOid;
888 
889 #ifdef NOT_USED
890  /* XXX this is unnecessary given the superuser check above */
891  /* Caller must own operator and its underlying function */
892  if (!pg_oper_ownercheck(operOid, GetUserId()))
894  get_opname(operOid));
895  funcOid = get_opcode(operOid);
896  if (!pg_proc_ownercheck(funcOid, GetUserId()))
898  get_func_name(funcOid));
899 #endif
900 
901  /* Save the info */
902  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
903  member->object = operOid;
904  member->number = item->number;
905  member->sortfamily = sortfamilyOid;
906  assignOperTypes(member, amoid, InvalidOid);
907  addFamilyMember(&operators, member, false);
908  break;
910  if (item->number <= 0 || item->number > maxProcNumber)
911  ereport(ERROR,
912  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
913  errmsg("invalid function number %d,"
914  " must be between 1 and %d",
915  item->number, maxProcNumber)));
916  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
917 #ifdef NOT_USED
918  /* XXX this is unnecessary given the superuser check above */
919  /* Caller must own function */
920  if (!pg_proc_ownercheck(funcOid, GetUserId()))
922  get_func_name(funcOid));
923 #endif
924 
925  /* Save the info */
926  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
927  member->object = funcOid;
928  member->number = item->number;
929 
930  /* allow overriding of the function's actual arg types */
931  if (item->class_args)
933  &member->lefttype, &member->righttype);
934 
935  assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
936  addFamilyMember(&procedures, member, true);
937  break;
939  ereport(ERROR,
940  (errcode(ERRCODE_SYNTAX_ERROR),
941  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
942  break;
943  default:
944  elog(ERROR, "unrecognized item type: %d", item->itemtype);
945  break;
946  }
947  }
948 
949  /*
950  * Add tuples to pg_amop and pg_amproc tying in the operators and
951  * functions. Dependencies on them are inserted, too.
952  */
953  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
954  InvalidOid, operators, true);
955  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
956  InvalidOid, procedures, true);
957 
958  /* make information available to event triggers */
959  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
960  operators, procedures);
961 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:140
#define NIL
Definition: pg_list.h:65
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1072
Oid GetUserId(void)
Definition: miscinit.c:448
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4772
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2605
char * get_opname(Oid opno)
Definition: lsyscache.c:1178
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1471
#define lfirst_node(type, lc)
Definition: pg_list.h:193
ObjectWithArgs * name
Definition: parsenodes.h:2613
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1327
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1043
void * palloc0(Size size)
Definition: mcxt.c:980
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1153
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2606
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2607
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:142
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1484
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1138
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2163
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1366
Definition: pg_list.h:50
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4798

◆ AlterOpFamilyDrop()

static void AlterOpFamilyDrop ( AlterOpFamilyStmt stmt,
Oid  amoid,
Oid  opfamilyoid,
int  maxOpNumber,
int  maxProcNumber,
List items 
)
static

Definition at line 967 of file opclasscmds.c.

References addFamilyMember(), CreateOpClassItem::class_args, dropOperators(), dropProcedures(), elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst_node, member, NIL, OpFamilyMember::number, CreateOpClassItem::number, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, AlterOpFamilyStmt::opfamilyname, palloc0(), processTypesSpec(), and OpFamilyMember::righttype.

Referenced by AlterOpFamily().

969 {
970  List *operators; /* OpFamilyMember list for operators */
971  List *procedures; /* OpFamilyMember list for support procs */
972  ListCell *l;
973 
974  operators = NIL;
975  procedures = NIL;
976 
977  /*
978  * Scan the "items" list to obtain additional info.
979  */
980  foreach(l, items)
981  {
983  Oid lefttype,
984  righttype;
986 
987  switch (item->itemtype)
988  {
990  if (item->number <= 0 || item->number > maxOpNumber)
991  ereport(ERROR,
992  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
993  errmsg("invalid operator number %d,"
994  " must be between 1 and %d",
995  item->number, maxOpNumber)));
996  processTypesSpec(item->class_args, &lefttype, &righttype);
997  /* Save the info */
998  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
999  member->number = item->number;
1000  member->lefttype = lefttype;
1001  member->righttype = righttype;
1002  addFamilyMember(&operators, member, false);
1003  break;
1004  case OPCLASS_ITEM_FUNCTION:
1005  if (item->number <= 0 || item->number > maxProcNumber)
1006  ereport(ERROR,
1007  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1008  errmsg("invalid function number %d,"
1009  " must be between 1 and %d",
1010  item->number, maxProcNumber)));
1011  processTypesSpec(item->class_args, &lefttype, &righttype);
1012  /* Save the info */
1013  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1014  member->number = item->number;
1015  member->lefttype = lefttype;
1016  member->righttype = righttype;
1017  addFamilyMember(&procedures, member, true);
1018  break;
1020  /* grammar prevents this from appearing */
1021  default:
1022  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1023  break;
1024  }
1025  }
1026 
1027  /*
1028  * Remove tuples from pg_amop and pg_amproc.
1029  */
1030  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1031  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1032 
1033  /* make information available to event triggers */
1034  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1035  operators, procedures);
1036 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1627
unsigned int Oid
Definition: postgres_ext.h:31
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2605
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1587
Oid member
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:193
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1327
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1043
void * palloc0(Size size)
Definition: mcxt.c:980
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2606
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2607
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
Definition: pg_list.h:50

◆ assignOperTypes()

static void assignOperTypes ( OpFamilyMember member,
Oid  amoid,
Oid  typeoid 
)
static

Definition at line 1072 of file opclasscmds.c.

References IndexAmRoutine::amcanorderbyop, elog, ereport, errcode(), errmsg(), ERROR, get_am_name(), GetIndexAmRoutineByAmId(), GETSTRUCT, HeapTupleIsValid, OpFamilyMember::lefttype, OpFamilyMember::object, ObjectIdGetDatum, OidIsValid, OPEROID, ReleaseSysCache(), OpFamilyMember::righttype, SearchSysCache1(), and OpFamilyMember::sortfamily.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1073 {
1074  Operator optup;
1075  Form_pg_operator opform;
1076 
1077  /* Fetch the operator definition */
1078  optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1079  if (!HeapTupleIsValid(optup))
1080  elog(ERROR, "cache lookup failed for operator %u", member->object);
1081  opform = (Form_pg_operator) GETSTRUCT(optup);
1082 
1083  /*
1084  * Opfamily operators must be binary.
1085  */
1086  if (opform->oprkind != 'b')
1087  ereport(ERROR,
1088  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1089  errmsg("index operators must be binary")));
1090 
1091  if (OidIsValid(member->sortfamily))
1092  {
1093  /*
1094  * Ordering op, check index supports that. (We could perhaps also
1095  * check that the operator returns a type supported by the sortfamily,
1096  * but that seems more trouble than it's worth here. If it does not,
1097  * the operator will never be matchable to any ORDER BY clause, but no
1098  * worse consequences can ensue. Also, trying to check that would
1099  * create an ordering hazard during dump/reload: it's possible that
1100  * the family has been created but not yet populated with the required
1101  * operators.)
1102  */
1103  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
1104 
1105  if (!amroutine->amcanorderbyop)
1106  ereport(ERROR,
1107  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1108  errmsg("access method \"%s\" does not support ordering operators",
1109  get_am_name(amoid))));
1110  }
1111  else
1112  {
1113  /*
1114  * Search operators must return boolean.
1115  */
1116  if (opform->oprresult != BOOLOID)
1117  ereport(ERROR,
1118  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1119  errmsg("index search operators must return boolean")));
1120  }
1121 
1122  /*
1123  * If lefttype/righttype isn't specified, use the operator's input types
1124  */
1125  if (!OidIsValid(member->lefttype))
1126  member->lefttype = opform->oprleft;
1127  if (!OidIsValid(member->righttype))
1128  member->righttype = opform->oprright;
1129 
1130  ReleaseSysCache(optup);
1131 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool amcanorderbyop
Definition: amapi.h:179
int errcode(int sqlerrcode)
Definition: elog.c:610
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
char * get_am_name(Oid amOid)
Definition: amcmds.c:219
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214

◆ assignProcTypes()

static void assignProcTypes ( OpFamilyMember member,
Oid  amoid,
Oid  typeoid,
int  opclassOptsProcNum 
)
static

Definition at line 1138 of file opclasscmds.c.

References BTEQUALIMAGE_PROC, BTINRANGE_PROC, BTORDER_PROC, BTSORTSUPPORT_PROC, elog, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, HASHEXTENDED_PROC, HASHSTANDARD_PROC, HeapTupleIsValid, OpFamilyMember::lefttype, OpFamilyMember::number, OpFamilyMember::object, ObjectIdGetDatum, OidIsValid, PROCOID, ReleaseSysCache(), OpFamilyMember::righttype, and SearchSysCache1().

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1140 {
1141  HeapTuple proctup;
1142  Form_pg_proc procform;
1143 
1144  /* Fetch the procedure definition */
1145  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1146  if (!HeapTupleIsValid(proctup))
1147  elog(ERROR, "cache lookup failed for function %u", member->object);
1148  procform = (Form_pg_proc) GETSTRUCT(proctup);
1149 
1150  /* Check the signature of the opclass options parsing function */
1151  if (member->number == opclassOptsProcNum)
1152  {
1153  if (OidIsValid(typeoid))
1154  {
1155  if ((OidIsValid(member->lefttype) && member->lefttype != typeoid) ||
1156  (OidIsValid(member->righttype) && member->righttype != typeoid))
1157  ereport(ERROR,
1158  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1159  errmsg("associated data types for opclass options parsing functions must match opclass input type")));
1160  }
1161  else
1162  {
1163  if (member->lefttype != member->righttype)
1164  ereport(ERROR,
1165  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1166  errmsg("left and right associated data types for opclass options parsing functions must match")));
1167  }
1168 
1169  if (procform->prorettype != VOIDOID ||
1170  procform->pronargs != 1 ||
1171  procform->proargtypes.values[0] != INTERNALOID)
1172  ereport(ERROR,
1173  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1174  errmsg("invalid opclass options parsing function"),
1175  errhint("Valid signature of opclass options parsing function is '%s'.",
1176  "(internal) RETURNS void")));
1177  }
1178 
1179  /*
1180  * btree comparison procs must be 2-arg procs returning int4. btree
1181  * sortsupport procs must take internal and return void. btree in_range
1182  * procs must be 5-arg procs returning bool. btree equalimage procs must
1183  * take 1 arg and return bool. hash support proc 1 must be a 1-arg proc
1184  * returning int4, while proc 2 must be a 2-arg proc returning int8.
1185  * Otherwise we don't know.
1186  */
1187  else if (amoid == BTREE_AM_OID)
1188  {
1189  if (member->number == BTORDER_PROC)
1190  {
1191  if (procform->pronargs != 2)
1192  ereport(ERROR,
1193  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1194  errmsg("btree comparison functions must have two arguments")));
1195  if (procform->prorettype != INT4OID)
1196  ereport(ERROR,
1197  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1198  errmsg("btree comparison functions must return integer")));
1199 
1200  /*
1201  * If lefttype/righttype isn't specified, use the proc's input
1202  * types
1203  */
1204  if (!OidIsValid(member->lefttype))
1205  member->lefttype = procform->proargtypes.values[0];
1206  if (!OidIsValid(member->righttype))
1207  member->righttype = procform->proargtypes.values[1];
1208  }
1209  else if (member->number == BTSORTSUPPORT_PROC)
1210  {
1211  if (procform->pronargs != 1 ||
1212  procform->proargtypes.values[0] != INTERNALOID)
1213  ereport(ERROR,
1214  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1215  errmsg("btree sort support functions must accept type \"internal\"")));
1216  if (procform->prorettype != VOIDOID)
1217  ereport(ERROR,
1218  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1219  errmsg("btree sort support functions must return void")));
1220 
1221  /*
1222  * Can't infer lefttype/righttype from proc, so use default rule
1223  */
1224  }
1225  else if (member->number == BTINRANGE_PROC)
1226  {
1227  if (procform->pronargs != 5)
1228  ereport(ERROR,
1229  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1230  errmsg("btree in_range functions must have five arguments")));
1231  if (procform->prorettype != BOOLOID)
1232  ereport(ERROR,
1233  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1234  errmsg("btree in_range functions must return boolean")));
1235 
1236  /*
1237  * If lefttype/righttype isn't specified, use the proc's input
1238  * types (we look at the test-value and offset arguments)
1239  */
1240  if (!OidIsValid(member->lefttype))
1241  member->lefttype = procform->proargtypes.values[0];
1242  if (!OidIsValid(member->righttype))
1243  member->righttype = procform->proargtypes.values[2];
1244  }
1245  else if (member->number == BTEQUALIMAGE_PROC)
1246  {
1247  if (procform->pronargs != 1)
1248  ereport(ERROR,
1249  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1250  errmsg("btree equal image functions must have one argument")));
1251  if (procform->prorettype != BOOLOID)
1252  ereport(ERROR,
1253  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1254  errmsg("btree equal image functions must return boolean")));
1255 
1256  /*
1257  * pg_amproc functions are indexed by (lefttype, righttype), but
1258  * an equalimage function can only be called at CREATE INDEX time.
1259  * The same opclass opcintype OID is always used for leftype and
1260  * righttype. Providing a cross-type routine isn't sensible.
1261  * Reject cross-type ALTER OPERATOR FAMILY ... ADD FUNCTION 4
1262  * statements here.
1263  */
1264  if (member->lefttype != member->righttype)
1265  ereport(ERROR,
1266  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1267  errmsg("btree equal image functions must not be cross-type")));
1268  }
1269  }
1270  else if (amoid == HASH_AM_OID)
1271  {
1272  if (member->number == HASHSTANDARD_PROC)
1273  {
1274  if (procform->pronargs != 1)
1275  ereport(ERROR,
1276  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1277  errmsg("hash function 1 must have one argument")));
1278  if (procform->prorettype != INT4OID)
1279  ereport(ERROR,
1280  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1281  errmsg("hash function 1 must return integer")));
1282  }
1283  else if (member->number == HASHEXTENDED_PROC)
1284  {
1285  if (procform->pronargs != 2)
1286  ereport(ERROR,
1287  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1288  errmsg("hash function 2 must have two arguments")));
1289  if (procform->prorettype != INT8OID)
1290  ereport(ERROR,
1291  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1292  errmsg("hash function 2 must return bigint")));
1293  }
1294 
1295  /*
1296  * If lefttype/righttype isn't specified, use the proc's input type
1297  */
1298  if (!OidIsValid(member->lefttype))
1299  member->lefttype = procform->proargtypes.values[0];
1300  if (!OidIsValid(member->righttype))
1301  member->righttype = procform->proargtypes.values[0];
1302  }
1303 
1304  /*
1305  * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1306  * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1307  * isn't available, so make the user specify the types.
1308  */
1309  if (!OidIsValid(member->lefttype))
1310  member->lefttype = typeoid;
1311  if (!OidIsValid(member->righttype))
1312  member->righttype = typeoid;
1313 
1314  if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1315  ereport(ERROR,
1316  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1317  errmsg("associated data types must be specified for index support function")));
1318 
1319  ReleaseSysCache(proctup);
1320 }
#define BTORDER_PROC
Definition: nbtree.h:575
int errhint(const char *fmt,...)
Definition: elog.c:1071
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:578
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:576
int errcode(int sqlerrcode)
Definition: elog.c:610
#define HASHEXTENDED_PROC
Definition: hash.h:354
#define OidIsValid(objectId)
Definition: c.h:644
#define BTINRANGE_PROC
Definition: nbtree.h:577
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define HASHSTANDARD_PROC
Definition: hash.h:353
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214

◆ CreateOpFamily()

static ObjectAddress CreateOpFamily ( const char *  amname,
const char *  opfname,
Oid  namespaceoid,
Oid  amoid 
)
static

Definition at line 246 of file opclasscmds.c.

References CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, NameGetDatum, namestrcpy(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OPFAMILYAMNAMENSP, OpfamilyOidIndexId, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, SearchSysCacheExists3, table_close(), table_open(), and values.

Referenced by DefineOpClass(), and DefineOpFamily().

247 {
248  Oid opfamilyoid;
249  Relation rel;
250  HeapTuple tup;
251  Datum values[Natts_pg_opfamily];
252  bool nulls[Natts_pg_opfamily];
253  NameData opfName;
254  ObjectAddress myself,
255  referenced;
256 
257  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
258 
259  /*
260  * Make sure there is no existing opfamily of this name (this is just to
261  * give a more friendly error message than "duplicate key").
262  */
264  ObjectIdGetDatum(amoid),
265  CStringGetDatum(opfname),
266  ObjectIdGetDatum(namespaceoid)))
267  ereport(ERROR,
269  errmsg("operator family \"%s\" for access method \"%s\" already exists",
270  opfname, amname)));
271 
272  /*
273  * Okay, let's create the pg_opfamily entry.
274  */
275  memset(values, 0, sizeof(values));
276  memset(nulls, false, sizeof(nulls));
277 
278  opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
279  Anum_pg_opfamily_oid);
280  values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
281  values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
282  namestrcpy(&opfName, opfname);
283  values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
284  values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
285  values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
286 
287  tup = heap_form_tuple(rel->rd_att, values, nulls);
288 
289  CatalogTupleInsert(rel, tup);
290 
291  heap_freetuple(tup);
292 
293  /*
294  * Create dependencies for the opfamily proper.
295  */
296  myself.classId = OperatorFamilyRelationId;
297  myself.objectId = opfamilyoid;
298  myself.objectSubId = 0;
299 
300  /* dependency on access method */
301  referenced.classId = AccessMethodRelationId;
302  referenced.objectId = amoid;
303  referenced.objectSubId = 0;
304  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
305 
306  /* dependency on namespace */
307  referenced.classId = NamespaceRelationId;
308  referenced.objectId = namespaceoid;
309  referenced.objectSubId = 0;
310  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
311 
312  /* dependency on owner */
313  recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
314 
315  /* dependency on extension */
316  recordDependencyOnCurrentExtension(&myself, false);
317 
318  /* Post creation hook for new operator family */
319  InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
320 
322 
323  return myself;
324 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
#define NameGetDatum(X)
Definition: postgres.h:595
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
Oid GetUserId(void)
Definition: miscinit.c:448
int errcode(int sqlerrcode)
Definition: elog.c:610
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
Definition: c.h:609
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define OpfamilyOidIndexId
Definition: indexing.h:207

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

Definition at line 331 of file opclasscmds.c.

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), AMNAME, CreateOpClassStmt::amname, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, assignOperTypes(), assignProcTypes(), BoolGetDatum, BTEqualStrategyNumber, CatalogTupleInsert(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum, CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, EventTriggerCollectCreateOpClass(), get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetIndexAmRoutineByAmId(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostCreateHook, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst_node, LookupFuncWithArgs(), LookupOperName(), LookupOperWithArgs(), member, CreateOpClassItem::name, NameGetDatum, NameStr, namestrcpy(), NIL, OpFamilyMember::number, CreateOpClassItem::number, ObjectWithArgs::objargs, OpFamilyMember::object, OBJECT_FUNCTION, OBJECT_OPERATOR, OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, ObjectWithArgs::objname, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, OpclassAmNameNspIndexId, CreateOpClassStmt::opclassname, OpclassOidIndexId, OPFAMILYAMNAMENSP, CreateOpClassStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), pg_namespace_aclcheck(), pg_oper_ownercheck(), pg_proc_ownercheck(), pg_type_ownercheck(), PointerGetDatum, processTypesSpec(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), ReleaseSysCache(), OpFamilyMember::righttype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1(), SearchSysCache3(), SearchSysCacheExists3, OpFamilyMember::sortfamily, CreateOpClassItem::storedtype, storeOperators(), storeProcedures(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

332 {
333  char *opcname; /* name of opclass we're creating */
334  Oid amoid, /* our AM's oid */
335  typeoid, /* indexable datatype oid */
336  storageoid, /* storage datatype oid, if any */
337  namespaceoid, /* namespace to create opclass in */
338  opfamilyoid, /* oid of containing opfamily */
339  opclassoid; /* oid of opclass we create */
340  int maxOpNumber, /* amstrategies value */
341  optsProcNumber, /* amoptsprocnum value */
342  maxProcNumber; /* amsupport value */
343  bool amstorage; /* amstorage flag */
344  List *operators; /* OpFamilyMember list for operators */
345  List *procedures; /* OpFamilyMember list for support procs */
346  ListCell *l;
347  Relation rel;
348  HeapTuple tup;
349  Form_pg_am amform;
350  IndexAmRoutine *amroutine;
351  Datum values[Natts_pg_opclass];
352  bool nulls[Natts_pg_opclass];
353  AclResult aclresult;
354  NameData opcName;
355  ObjectAddress myself,
356  referenced;
357 
358  /* Convert list of names to a name and namespace */
359  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
360  &opcname);
361 
362  /* Check we have creation rights in target namespace */
363  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
364  if (aclresult != ACLCHECK_OK)
365  aclcheck_error(aclresult, OBJECT_SCHEMA,
366  get_namespace_name(namespaceoid));
367 
368  /* Get necessary info about access method */
370  if (!HeapTupleIsValid(tup))
371  ereport(ERROR,
372  (errcode(ERRCODE_UNDEFINED_OBJECT),
373  errmsg("access method \"%s\" does not exist",
374  stmt->amname)));
375 
376  amform = (Form_pg_am) GETSTRUCT(tup);
377  amoid = amform->oid;
378  amroutine = GetIndexAmRoutineByAmId(amoid, false);
379  ReleaseSysCache(tup);
380 
381  maxOpNumber = amroutine->amstrategies;
382  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
383  if (maxOpNumber <= 0)
384  maxOpNumber = SHRT_MAX;
385  maxProcNumber = amroutine->amsupport;
386  optsProcNumber = amroutine->amoptsprocnum;
387  amstorage = amroutine->amstorage;
388 
389  /* XXX Should we make any privilege check against the AM? */
390 
391  /*
392  * The question of appropriate permissions for CREATE OPERATOR CLASS is
393  * interesting. Creating an opclass is tantamount to granting public
394  * execute access on the functions involved, since the index machinery
395  * generally does not check access permission before using the functions.
396  * A minimum expectation therefore is that the caller have execute
397  * privilege with grant option. Since we don't have a way to make the
398  * opclass go away if the grant option is revoked, we choose instead to
399  * require ownership of the functions. It's also not entirely clear what
400  * permissions should be required on the datatype, but ownership seems
401  * like a safe choice.
402  *
403  * Currently, we require superuser privileges to create an opclass. This
404  * seems necessary because we have no way to validate that the offered set
405  * of operators and functions are consistent with the AM's expectations.
406  * It would be nice to provide such a check someday, if it can be done
407  * without solving the halting problem :-(
408  *
409  * XXX re-enable NOT_USED code sections below if you remove this test.
410  */
411  if (!superuser())
412  ereport(ERROR,
413  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
414  errmsg("must be superuser to create an operator class")));
415 
416  /* Look up the datatype */
417  typeoid = typenameTypeId(NULL, stmt->datatype);
418 
419 #ifdef NOT_USED
420  /* XXX this is unnecessary given the superuser check above */
421  /* Check we have ownership of the datatype */
422  if (!pg_type_ownercheck(typeoid, GetUserId()))
424 #endif
425 
426  /*
427  * Look up the containing operator family, or create one if FAMILY option
428  * was omitted and there's not a match already.
429  */
430  if (stmt->opfamilyname)
431  {
432  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
433  }
434  else
435  {
436  /* Lookup existing family of same name and namespace */
438  ObjectIdGetDatum(amoid),
439  PointerGetDatum(opcname),
440  ObjectIdGetDatum(namespaceoid));
441  if (HeapTupleIsValid(tup))
442  {
443  opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
444 
445  /*
446  * XXX given the superuser check above, there's no need for an
447  * ownership check here
448  */
449  ReleaseSysCache(tup);
450  }
451  else
452  {
453  ObjectAddress tmpAddr;
454 
455  /*
456  * Create it ... again no need for more permissions ...
457  */
458  tmpAddr = CreateOpFamily(stmt->amname, opcname,
459  namespaceoid, amoid);
460  opfamilyoid = tmpAddr.objectId;
461  }
462  }
463 
464  operators = NIL;
465  procedures = NIL;
466 
467  /* Storage datatype is optional */
468  storageoid = InvalidOid;
469 
470  /*
471  * Scan the "items" list to obtain additional info.
472  */
473  foreach(l, stmt->items)
474  {
476  Oid operOid;
477  Oid funcOid;
478  Oid sortfamilyOid;
480 
481  switch (item->itemtype)
482  {
484  if (item->number <= 0 || item->number > maxOpNumber)
485  ereport(ERROR,
486  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
487  errmsg("invalid operator number %d,"
488  " must be between 1 and %d",
489  item->number, maxOpNumber)));
490  if (item->name->objargs != NIL)
491  operOid = LookupOperWithArgs(item->name, false);
492  else
493  {
494  /* Default to binary op on input datatype */
495  operOid = LookupOperName(NULL, item->name->objname,
496  typeoid, typeoid,
497  false, -1);
498  }
499 
500  if (item->order_family)
501  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
502  item->order_family,
503  false);
504  else
505  sortfamilyOid = InvalidOid;
506 
507 #ifdef NOT_USED
508  /* XXX this is unnecessary given the superuser check above */
509  /* Caller must own operator and its underlying function */
510  if (!pg_oper_ownercheck(operOid, GetUserId()))
512  get_opname(operOid));
513  funcOid = get_opcode(operOid);
514  if (!pg_proc_ownercheck(funcOid, GetUserId()))
516  get_func_name(funcOid));
517 #endif
518 
519  /* Save the info */
520  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
521  member->object = operOid;
522  member->number = item->number;
523  member->sortfamily = sortfamilyOid;
524  assignOperTypes(member, amoid, typeoid);
525  addFamilyMember(&operators, member, false);
526  break;
528  if (item->number <= 0 || item->number > maxProcNumber)
529  ereport(ERROR,
530  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
531  errmsg("invalid function number %d,"
532  " must be between 1 and %d",
533  item->number, maxProcNumber)));
534  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
535 #ifdef NOT_USED
536  /* XXX this is unnecessary given the superuser check above */
537  /* Caller must own function */
538  if (!pg_proc_ownercheck(funcOid, GetUserId()))
540  get_func_name(funcOid));
541 #endif
542  /* Save the info */
543  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
544  member->object = funcOid;
545  member->number = item->number;
546 
547  /* allow overriding of the function's actual arg types */
548  if (item->class_args)
550  &member->lefttype, &member->righttype);
551 
552  assignProcTypes(member, amoid, typeoid, optsProcNumber);
553  addFamilyMember(&procedures, member, true);
554  break;
556  if (OidIsValid(storageoid))
557  ereport(ERROR,
558  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
559  errmsg("storage type specified more than once")));
560  storageoid = typenameTypeId(NULL, item->storedtype);
561 
562 #ifdef NOT_USED
563  /* XXX this is unnecessary given the superuser check above */
564  /* Check we have ownership of the datatype */
565  if (!pg_type_ownercheck(storageoid, GetUserId()))
567 #endif
568  break;
569  default:
570  elog(ERROR, "unrecognized item type: %d", item->itemtype);
571  break;
572  }
573  }
574 
575  /*
576  * If storagetype is specified, make sure it's legal.
577  */
578  if (OidIsValid(storageoid))
579  {
580  /* Just drop the spec if same as column datatype */
581  if (storageoid == typeoid)
582  storageoid = InvalidOid;
583  else if (!amstorage)
584  ereport(ERROR,
585  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
586  errmsg("storage type cannot be different from data type for access method \"%s\"",
587  stmt->amname)));
588  }
589 
590  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
591 
592  /*
593  * Make sure there is no existing opclass of this name (this is just to
594  * give a more friendly error message than "duplicate key").
595  */
597  ObjectIdGetDatum(amoid),
598  CStringGetDatum(opcname),
599  ObjectIdGetDatum(namespaceoid)))
600  ereport(ERROR,
602  errmsg("operator class \"%s\" for access method \"%s\" already exists",
603  opcname, stmt->amname)));
604 
605  /*
606  * If we are creating a default opclass, check there isn't one already.
607  * (Note we do not restrict this test to visible opclasses; this ensures
608  * that typcache.c can find unique solutions to its questions.)
609  */
610  if (stmt->isDefault)
611  {
612  ScanKeyData skey[1];
613  SysScanDesc scan;
614 
615  ScanKeyInit(&skey[0],
616  Anum_pg_opclass_opcmethod,
617  BTEqualStrategyNumber, F_OIDEQ,
618  ObjectIdGetDatum(amoid));
619 
621  NULL, 1, skey);
622 
623  while (HeapTupleIsValid(tup = systable_getnext(scan)))
624  {
625  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
626 
627  if (opclass->opcintype == typeoid && opclass->opcdefault)
628  ereport(ERROR,
630  errmsg("could not make operator class \"%s\" be default for type %s",
631  opcname,
632  TypeNameToString(stmt->datatype)),
633  errdetail("Operator class \"%s\" already is the default.",
634  NameStr(opclass->opcname))));
635  }
636 
637  systable_endscan(scan);
638  }
639 
640  /*
641  * Okay, let's create the pg_opclass entry.
642  */
643  memset(values, 0, sizeof(values));
644  memset(nulls, false, sizeof(nulls));
645 
646  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
647  Anum_pg_opclass_oid);
648  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
649  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
650  namestrcpy(&opcName, opcname);
651  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
652  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
653  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
654  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
655  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
656  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
657  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
658 
659  tup = heap_form_tuple(rel->rd_att, values, nulls);
660 
661  CatalogTupleInsert(rel, tup);
662 
663  heap_freetuple(tup);
664 
665  /*
666  * Now add tuples to pg_amop and pg_amproc tying in the operators and
667  * functions. Dependencies on them are inserted, too.
668  */
669  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
670  opclassoid, operators, false);
671  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
672  opclassoid, procedures, false);
673 
674  /* let event triggers know what happened */
675  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
676 
677  /*
678  * Create dependencies for the opclass proper. Note: we do not need a
679  * dependency link to the AM, because that exists through the opfamily.
680  */
681  myself.classId = OperatorClassRelationId;
682  myself.objectId = opclassoid;
683  myself.objectSubId = 0;
684 
685  /* dependency on namespace */
686  referenced.classId = NamespaceRelationId;
687  referenced.objectId = namespaceoid;
688  referenced.objectSubId = 0;
689  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
690 
691  /* dependency on opfamily */
692  referenced.classId = OperatorFamilyRelationId;
693  referenced.objectId = opfamilyoid;
694  referenced.objectSubId = 0;
695  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
696 
697  /* dependency on indexed datatype */
698  referenced.classId = TypeRelationId;
699  referenced.objectId = typeoid;
700  referenced.objectSubId = 0;
701  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
702 
703  /* dependency on storage datatype */
704  if (OidIsValid(storageoid))
705  {
706  referenced.classId = TypeRelationId;
707  referenced.objectId = storageoid;
708  referenced.objectSubId = 0;
709  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
710  }
711 
712  /* dependency on owner */
713  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
714 
715  /* dependency on extension */
716  recordDependencyOnCurrentExtension(&myself, false);
717 
718  /* Post creation hook for new operator class */
719  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
720 
722 
723  return myself;
724 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:140
#define NIL
Definition: pg_list.h:65
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
#define NameGetDatum(X)
Definition: postgres.h:595
uint16 amsupport
Definition: amapi.h:173
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1072
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
Oid GetUserId(void)
Definition: miscinit.c:448
TypeName * storedtype
Definition: parsenodes.h:2619
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
#define PointerGetDatum(X)
Definition: postgres.h:556
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
bool amstorage
Definition: amapi.h:193
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4772
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:102
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4746
int namestrcpy(Name name, const char *str)
Definition: name.c:250
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4658
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
#define OpclassAmNameNspIndexId
Definition: indexing.h:195
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3640
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2605
char * get_opname(Oid opno)
Definition: lsyscache.c:1178
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1471
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Definition: c.h:609
TypeName * datatype
Definition: parsenodes.h:2600
ObjectWithArgs * name
Definition: parsenodes.h:2613
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1327
#define CStringGetDatum(X)
Definition: postgres.h:578
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:246
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1043
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void * palloc0(Size size)
Definition: mcxt.c:980
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
TupleDesc rd_att
Definition: rel.h:110
#define OpclassOidIndexId
Definition: indexing.h:197
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1153
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2606
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2607
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:142
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1484
uint16 amstrategies
Definition: amapi.h:171
static Datum values[MAXATTR]
Definition: bootstrap.c:167
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1138
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:824
uint16 amoptsprocnum
Definition: amapi.h:175
#define elog(elevel,...)
Definition: elog.h:214
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2163
#define NameStr(name)
Definition: c.h:615
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1366
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
Definition: pg_list.h:50
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4798
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

Definition at line 732 of file opclasscmds.c.

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, CreateOpFamilyStmt::amname, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_index_am_oid(), get_namespace_name(), GetUserId(), OBJECT_SCHEMA, CreateOpFamilyStmt::opfamilyname, pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), and superuser().

Referenced by ProcessUtilitySlow().

733 {
734  char *opfname; /* name of opfamily we're creating */
735  Oid amoid, /* our AM's oid */
736  namespaceoid; /* namespace to create opfamily in */
737  AclResult aclresult;
738 
739  /* Convert list of names to a name and namespace */
740  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
741  &opfname);
742 
743  /* Check we have creation rights in target namespace */
744  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
745  if (aclresult != ACLCHECK_OK)
746  aclcheck_error(aclresult, OBJECT_SCHEMA,
747  get_namespace_name(namespaceoid));
748 
749  /* Get access method OID, throwing an error if it doesn't exist. */
750  amoid = get_index_am_oid(stmt->amname, false);
751 
752  /* XXX Should we make any privilege check against the AM? */
753 
754  /*
755  * Currently, we require superuser privileges to create an opfamily. See
756  * comments in DefineOpClass.
757  */
758  if (!superuser())
759  ereport(ERROR,
760  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
761  errmsg("must be superuser to create an operator family")));
762 
763  /* Insert pg_opfamily catalog entry */
764  return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
765 }
Oid GetUserId(void)
Definition: miscinit.c:448
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4658
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3327
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:190
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:246
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ dropOperators()

static void dropOperators ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
List operators 
)
static

Definition at line 1587 of file opclasscmds.c.

References AMOPSTRATEGY, DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid4, Int16GetDatum, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, ObjectIdGetDatum, OidIsValid, performDeletion(), and OpFamilyMember::righttype.

Referenced by AlterOpFamilyDrop().

1589 {
1590  ListCell *l;
1591 
1592  foreach(l, operators)
1593  {
1594  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1595  Oid amopid;
1596  ObjectAddress object;
1597 
1598  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1599  ObjectIdGetDatum(opfamilyoid),
1602  Int16GetDatum(op->number));
1603  if (!OidIsValid(amopid))
1604  ereport(ERROR,
1605  (errcode(ERRCODE_UNDEFINED_OBJECT),
1606  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1607  op->number,
1608  format_type_be(op->lefttype),
1610  NameListToString(opfamilyname))));
1611 
1612  object.classId = AccessMethodOperatorRelationId;
1613  object.objectId = amopid;
1614  object.objectSubId = 0;
1615 
1616  performDeletion(&object, DROP_RESTRICT, 0);
1617  }
1618 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:314
char * NameListToString(List *names)
Definition: namespace.c:3102
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ dropProcedures()

static void dropProcedures ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
List procedures 
)
static

Definition at line 1627 of file opclasscmds.c.

References AMPROCNUM, DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid4, Int16GetDatum, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, ObjectIdGetDatum, OidIsValid, performDeletion(), and OpFamilyMember::righttype.

Referenced by AlterOpFamilyDrop().

1629 {
1630  ListCell *l;
1631 
1632  foreach(l, procedures)
1633  {
1634  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1635  Oid amprocid;
1636  ObjectAddress object;
1637 
1638  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1639  ObjectIdGetDatum(opfamilyoid),
1642  Int16GetDatum(op->number));
1643  if (!OidIsValid(amprocid))
1644  ereport(ERROR,
1645  (errcode(ERRCODE_UNDEFINED_OBJECT),
1646  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1647  op->number,
1648  format_type_be(op->lefttype),
1650  NameListToString(opfamilyname))));
1651 
1652  object.classId = AccessMethodProcedureRelationId;
1653  object.objectId = amprocid;
1654  object.objectSubId = 0;
1655 
1656  performDeletion(&object, DROP_RESTRICT, 0);
1657  }
1658 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:314
char * NameListToString(List *names)
Definition: namespace.c:3102
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ get_opclass_oid()

Oid get_opclass_oid ( Oid  amID,
List opclassname,
bool  missing_ok 
)

Definition at line 223 of file opclasscmds.c.

References GETSTRUCT, HeapTupleIsValid, InvalidOid, OpClassCacheLookup(), and ReleaseSysCache().

Referenced by findRangeSubOpclass(), get_object_address_opcf(), and resolve_unique_index_expr().

224 {
225  HeapTuple htup;
226  Form_pg_opclass opcform;
227  Oid opcID;
228 
229  htup = OpClassCacheLookup(amID, opclassname, missing_ok);
230  if (!HeapTupleIsValid(htup))
231  return InvalidOid;
232  opcform = (Form_pg_opclass) GETSTRUCT(htup);
233  opcID = opcform->oid;
234  ReleaseSysCache(htup);
235 
236  return opcID;
237 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:165
unsigned int Oid
Definition: postgres_ext.h:31
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83

◆ get_opfamily_oid()

Oid get_opfamily_oid ( Oid  amID,
List opfamilyname,
bool  missing_ok 
)

Definition at line 142 of file opclasscmds.c.

References GETSTRUCT, HeapTupleIsValid, InvalidOid, OpFamilyCacheLookup(), and ReleaseSysCache().

Referenced by AlterOpFamily(), AlterOpFamilyAdd(), DefineOpClass(), and get_object_address_opcf().

143 {
144  HeapTuple htup;
145  Form_pg_opfamily opfamform;
146  Oid opfID;
147 
148  htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
149  if (!HeapTupleIsValid(htup))
150  return InvalidOid;
151  opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
152  opfID = opfamform->oid;
153  ReleaseSysCache(htup);
154 
155  return opfID;
156 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:84
unsigned int Oid
Definition: postgres_ext.h:31
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78

◆ IsThereOpClassInNamespace()

void IsThereOpClassInNamespace ( const char *  opcname,
Oid  opcmethod,
Oid  opcnamespace 
)

Definition at line 1766 of file opclasscmds.c.

References CLAAMNAMENSP, CStringGetDatum, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

1768 {
1769  /* make sure the new name doesn't exist */
1771  ObjectIdGetDatum(opcmethod),
1772  CStringGetDatum(opcname),
1773  ObjectIdGetDatum(opcnamespace)))
1774  ereport(ERROR,
1776  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1777  opcname,
1778  get_am_name(opcmethod),
1779  get_namespace_name(opcnamespace))));
1780 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
char * get_am_name(Oid amOid)
Definition: amcmds.c:219
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ IsThereOpFamilyInNamespace()

void IsThereOpFamilyInNamespace ( const char *  opfname,
Oid  opfmethod,
Oid  opfnamespace 
)

Definition at line 1789 of file opclasscmds.c.

References CStringGetDatum, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, OPFAMILYAMNAMENSP, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

1791 {
1792  /* make sure the new name doesn't exist */
1794  ObjectIdGetDatum(opfmethod),
1795  CStringGetDatum(opfname),
1796  ObjectIdGetDatum(opfnamespace)))
1797  ereport(ERROR,
1799  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1800  opfname,
1801  get_am_name(opfmethod),
1802  get_namespace_name(opfnamespace))));
1803 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3155
char * get_am_name(Oid amOid)
Definition: amcmds.c:219
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ OpClassCacheLookup()

static HeapTuple OpClassCacheLookup ( Oid  amID,
List opclassname,
bool  missing_ok 
)
static

Definition at line 165 of file opclasscmds.c.

References AMOID, CLAAMNAMENSP, CLAOID, DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, LookupExplicitNamespace(), NameListToString(), NameStr, ObjectIdGetDatum, OidIsValid, OpclassnameGetOpcid(), PointerGetDatum, SearchSysCache1(), and SearchSysCache3().

Referenced by get_opclass_oid().

166 {
167  char *schemaname;
168  char *opcname;
169  HeapTuple htup;
170 
171  /* deconstruct the name list */
172  DeconstructQualifiedName(opclassname, &schemaname, &opcname);
173 
174  if (schemaname)
175  {
176  /* Look in specific schema only */
177  Oid namespaceId;
178 
179  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180  if (!OidIsValid(namespaceId))
181  htup = NULL;
182  else
184  ObjectIdGetDatum(amID),
185  PointerGetDatum(opcname),
186  ObjectIdGetDatum(namespaceId));
187  }
188  else
189  {
190  /* Unqualified opclass name, so search the search path */
191  Oid opcID = OpclassnameGetOpcid(amID, opcname);
192 
193  if (!OidIsValid(opcID))
194  htup = NULL;
195  else
196  htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
197  }
198 
199  if (!HeapTupleIsValid(htup) && !missing_ok)
200  {
201  HeapTuple amtup;
202 
203  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
204  if (!HeapTupleIsValid(amtup))
205  elog(ERROR, "cache lookup failed for access method %u", amID);
206  ereport(ERROR,
207  (errcode(ERRCODE_UNDEFINED_OBJECT),
208  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
209  NameListToString(opclassname),
210  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
211  }
212 
213  return htup;
214 }
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2893
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Definition: syscache.h:36
#define PointerGetDatum(X)
Definition: postgres.h:556
int errcode(int sqlerrcode)
Definition: elog.c:610
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2809
unsigned int Oid
Definition: postgres_ext.h:31
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1800
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615

◆ OpFamilyCacheLookup()

static HeapTuple OpFamilyCacheLookup ( Oid  amID,
List opfamilyname,
bool  missing_ok 
)
static

Definition at line 84 of file opclasscmds.c.

References AMOID, DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, LookupExplicitNamespace(), NameListToString(), NameStr, ObjectIdGetDatum, OidIsValid, OPFAMILYAMNAMENSP, OpfamilynameGetOpfid(), OPFAMILYOID, PointerGetDatum, SearchSysCache1(), and SearchSysCache3().

Referenced by get_opfamily_oid().

85 {
86  char *schemaname;
87  char *opfname;
88  HeapTuple htup;
89 
90  /* deconstruct the name list */
91  DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
92 
93  if (schemaname)
94  {
95  /* Look in specific schema only */
96  Oid namespaceId;
97 
98  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
99  if (!OidIsValid(namespaceId))
100  htup = NULL;
101  else
103  ObjectIdGetDatum(amID),
104  PointerGetDatum(opfname),
105  ObjectIdGetDatum(namespaceId));
106  }
107  else
108  {
109  /* Unqualified opfamily name, so search the search path */
110  Oid opfID = OpfamilynameGetOpfid(amID, opfname);
111 
112  if (!OidIsValid(opfID))
113  htup = NULL;
114  else
116  }
117 
118  if (!HeapTupleIsValid(htup) && !missing_ok)
119  {
120  HeapTuple amtup;
121 
122  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
123  if (!HeapTupleIsValid(amtup))
124  elog(ERROR, "cache lookup failed for access method %u", amID);
125  ereport(ERROR,
126  (errcode(ERRCODE_UNDEFINED_OBJECT),
127  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
128  NameListToString(opfamilyname),
129  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
130  }
131 
132  return htup;
133 }
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2893
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Definition: syscache.h:36
#define PointerGetDatum(X)
Definition: postgres.h:556
int errcode(int sqlerrcode)
Definition: elog.c:610
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2809
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
Oid OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1883
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615

◆ processTypesSpec()

static void processTypesSpec ( List args,
Oid lefttype,
Oid righttype 
)
static

Definition at line 1043 of file opclasscmds.c.

References Assert, ereport, errcode(), errmsg(), ERROR, linitial, list_length(), lsecond, NIL, and typenameTypeId().

Referenced by AlterOpFamilyAdd(), AlterOpFamilyDrop(), and DefineOpClass().

1044 {
1045  TypeName *typeName;
1046 
1047  Assert(args != NIL);
1048 
1049  typeName = (TypeName *) linitial(args);
1050  *lefttype = typenameTypeId(NULL, typeName);
1051 
1052  if (list_length(args) > 1)
1053  {
1054  typeName = (TypeName *) lsecond(args);
1055  *righttype = typenameTypeId(NULL, typeName);
1056  }
1057  else
1058  *righttype = *lefttype;
1059 
1060  if (list_length(args) > 2)
1061  ereport(ERROR,
1062  (errcode(ERRCODE_SYNTAX_ERROR),
1063  errmsg("one or two argument types must be specified")));
1064 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
#define lsecond(l)
Definition: pg_list.h:200
#define linitial(l)
Definition: pg_list.h:195
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:738
static int list_length(const List *l)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:824
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ RemoveAmOpEntryById()

void RemoveAmOpEntryById ( Oid  entryOid)

Definition at line 1702 of file opclasscmds.c.

References AccessMethodOperatorOidIndexId, BTEqualStrategyNumber, CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

1703 {
1704  Relation rel;
1705  HeapTuple tup;
1706  ScanKeyData skey[1];
1707  SysScanDesc scan;
1708 
1709  ScanKeyInit(&skey[0],
1710  Anum_pg_amop_oid,
1711  BTEqualStrategyNumber, F_OIDEQ,
1712  ObjectIdGetDatum(entryOid));
1713 
1714  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1715 
1717  NULL, 1, skey);
1718 
1719  /* we expect exactly one match */
1720  tup = systable_getnext(scan);
1721  if (!HeapTupleIsValid(tup))
1722  elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1723 
1724  CatalogTupleDelete(rel, &tup->t_self);
1725 
1726  systable_endscan(scan);
1728 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define AccessMethodOperatorOidIndexId
Definition: indexing.h:81
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ RemoveAmProcEntryById()

void RemoveAmProcEntryById ( Oid  entryOid)

Definition at line 1731 of file opclasscmds.c.

References AccessMethodProcedureOidIndexId, BTEqualStrategyNumber, CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

1732 {
1733  Relation rel;
1734  HeapTuple tup;
1735  ScanKeyData skey[1];
1736  SysScanDesc scan;
1737 
1738  ScanKeyInit(&skey[0],
1739  Anum_pg_amproc_oid,
1740  BTEqualStrategyNumber, F_OIDEQ,
1741  ObjectIdGetDatum(entryOid));
1742 
1743  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1744 
1746  NULL, 1, skey);
1747 
1748  /* we expect exactly one match */
1749  tup = systable_getnext(scan);
1750  if (!HeapTupleIsValid(tup))
1751  elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1752 
1753  CatalogTupleDelete(rel, &tup->t_self);
1754 
1755  systable_endscan(scan);
1757 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
#define AccessMethodProcedureOidIndexId
Definition: indexing.h:86
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ RemoveOpClassById()

void RemoveOpClassById ( Oid  opclassOid)

Definition at line 1683 of file opclasscmds.c.

References CatalogTupleDelete(), CLAOID, elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

1684 {
1685  Relation rel;
1686  HeapTuple tup;
1687 
1688  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
1689 
1690  tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1691  if (!HeapTupleIsValid(tup)) /* should not happen */
1692  elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1693 
1694  CatalogTupleDelete(rel, &tup->t_self);
1695 
1696  ReleaseSysCache(tup);
1697 
1699 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ RemoveOpFamilyById()

void RemoveOpFamilyById ( Oid  opfamilyOid)

Definition at line 1664 of file opclasscmds.c.

References CatalogTupleDelete(), elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum, OPFAMILYOID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

1665 {
1666  Relation rel;
1667  HeapTuple tup;
1668 
1669  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
1670 
1671  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1672  if (!HeapTupleIsValid(tup)) /* should not happen */
1673  elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1674 
1675  CatalogTupleDelete(rel, &tup->t_self);
1676 
1677  ReleaseSysCache(tup);
1678 
1680 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:214
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ storeOperators()

static void storeOperators ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
Oid  opclassoid,
List operators,
bool  isAdd 
)
static

Definition at line 1366 of file opclasscmds.c.

References AccessMethodOperatorOidIndexId, AMOPSTRATEGY, CatalogTupleInsert(), CharGetDatum, ObjectAddress::classId, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), Int16GetDatum, InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_att, recordDependencyOn(), OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, OpFamilyMember::sortfamily, table_close(), table_open(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1369 {
1370  Relation rel;
1371  Datum values[Natts_pg_amop];
1372  bool nulls[Natts_pg_amop];
1373  HeapTuple tup;
1374  Oid entryoid;
1375  ObjectAddress myself,
1376  referenced;
1377  ListCell *l;
1378 
1379  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1380 
1381  foreach(l, operators)
1382  {
1383  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1384  char oppurpose;
1385 
1386  /*
1387  * If adding to an existing family, check for conflict with an
1388  * existing pg_amop entry (just to give a nicer error message)
1389  */
1390  if (isAdd &&
1392  ObjectIdGetDatum(opfamilyoid),
1395  Int16GetDatum(op->number)))
1396  ereport(ERROR,
1398  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1399  op->number,
1400  format_type_be(op->lefttype),
1402  NameListToString(opfamilyname))));
1403 
1404  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1405 
1406  /* Create the pg_amop entry */
1407  memset(values, 0, sizeof(values));
1408  memset(nulls, false, sizeof(nulls));
1409 
1411  Anum_pg_amop_oid);
1412  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1413  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1414  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1415  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1416  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1417  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1418  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1419  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1420  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1421 
1422  tup = heap_form_tuple(rel->rd_att, values, nulls);
1423 
1424  CatalogTupleInsert(rel, tup);
1425 
1426  heap_freetuple(tup);
1427 
1428  /* Make its dependencies */
1429  myself.classId = AccessMethodOperatorRelationId;
1430  myself.objectId = entryoid;
1431  myself.objectSubId = 0;
1432 
1433  referenced.classId = OperatorRelationId;
1434  referenced.objectId = op->object;
1435  referenced.objectSubId = 0;
1436 
1437  if (OidIsValid(opclassoid))
1438  {
1439  /* if contained in an opclass, use a NORMAL dep on operator */
1440  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1441 
1442  /* ... and an INTERNAL dep on the opclass */
1443  referenced.classId = OperatorClassRelationId;
1444  referenced.objectId = opclassoid;
1445  referenced.objectSubId = 0;
1446  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1447  }
1448  else
1449  {
1450  /* if "loose" in the opfamily, use a AUTO dep on operator */
1451  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1452 
1453  /* ... and an AUTO dep on the opfamily */
1454  referenced.classId = OperatorFamilyRelationId;
1455  referenced.objectId = opfamilyoid;
1456  referenced.objectSubId = 0;
1457  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1458  }
1459 
1460  /* A search operator also needs a dep on the referenced opfamily */
1461  if (OidIsValid(op->sortfamily))
1462  {
1463  referenced.classId = OperatorFamilyRelationId;
1464  referenced.objectId = op->sortfamily;
1465  referenced.objectSubId = 0;
1466  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1467  }
1468  /* Post create hook of this access method operator */
1469  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1470  entryoid, 0);
1471  }
1472 
1474 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define Int16GetDatum(X)
Definition: postgres.h:451
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:189
#define AccessMethodOperatorOidIndexId
Definition: indexing.h:81
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
char * NameListToString(List *names)
Definition: namespace.c:3102
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183

◆ storeProcedures()

static void storeProcedures ( List opfamilyname,
Oid  amoid,
Oid  opfamilyoid,
Oid  opclassoid,
List procedures,
bool  isAdd 
)
static

Definition at line 1484 of file opclasscmds.c.

References AccessMethodProcedureOidIndexId, AMPROCNUM, CatalogTupleInsert(), ObjectAddress::classId, DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, format_type_be(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), Int16GetDatum, InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, RelationData::rd_att, recordDependencyOn(), OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, table_close(), table_open(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1487 {
1488  Relation rel;
1489  Datum values[Natts_pg_amproc];
1490  bool nulls[Natts_pg_amproc];
1491  HeapTuple tup;
1492  Oid entryoid;
1493  ObjectAddress myself,
1494  referenced;
1495  ListCell *l;
1496 
1497  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1498 
1499  foreach(l, procedures)
1500  {
1501  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1502 
1503  /*
1504  * If adding to an existing family, check for conflict with an
1505  * existing pg_amproc entry (just to give a nicer error message)
1506  */
1507  if (isAdd &&
1509  ObjectIdGetDatum(opfamilyoid),
1510  ObjectIdGetDatum(proc->lefttype),
1511  ObjectIdGetDatum(proc->righttype),
1512  Int16GetDatum(proc->number)))
1513  ereport(ERROR,
1515  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1516  proc->number,
1517  format_type_be(proc->lefttype),
1518  format_type_be(proc->righttype),
1519  NameListToString(opfamilyname))));
1520 
1521  /* Create the pg_amproc entry */
1522  memset(values, 0, sizeof(values));
1523  memset(nulls, false, sizeof(nulls));
1524 
1526  Anum_pg_amproc_oid);
1527  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1528  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1529  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1530  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1531  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1532  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1533 
1534  tup = heap_form_tuple(rel->rd_att, values, nulls);
1535 
1536  CatalogTupleInsert(rel, tup);
1537 
1538  heap_freetuple(tup);
1539 
1540  /* Make its dependencies */
1541  myself.classId = AccessMethodProcedureRelationId;
1542  myself.objectId = entryoid;
1543  myself.objectSubId = 0;
1544 
1545  referenced.classId = ProcedureRelationId;
1546  referenced.objectId = proc->object;
1547  referenced.objectSubId = 0;
1548 
1549  if (OidIsValid(opclassoid))
1550  {
1551  /* if contained in an opclass, use a NORMAL dep on procedure */
1552  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1553 
1554  /* ... and an INTERNAL dep on the opclass */
1555  referenced.classId = OperatorClassRelationId;
1556  referenced.objectId = opclassoid;
1557  referenced.objectSubId = 0;
1558  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1559  }
1560  else
1561  {
1562  /* if "loose" in the opfamily, use a AUTO dep on procedure */
1563  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1564 
1565  /* ... and an AUTO dep on the opfamily */
1566  referenced.classId = OperatorFamilyRelationId;
1567  referenced.objectId = opfamilyoid;
1568  referenced.objectSubId = 0;
1569  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1570  }
1571  /* Post create hook of access method procedure */
1572  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1573  entryoid, 0);
1574  }
1575 
1577 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define Int16GetDatum(X)
Definition: postgres.h:451
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:189
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:327
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define AccessMethodProcedureOidIndexId
Definition: indexing.h:86
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
char * NameListToString(List *names)
Definition: namespace.c:3102
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:190
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:824
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183