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/nbtree.h"
#include "access/htup_details.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, 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)
 
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 1267 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().

1268 {
1269  ListCell *l;
1270 
1271  foreach(l, *list)
1272  {
1273  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1274 
1275  if (old->number == member->number &&
1276  old->lefttype == member->lefttype &&
1277  old->righttype == member->righttype)
1278  {
1279  if (isProc)
1280  ereport(ERROR,
1281  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1282  errmsg("function number %d for (%s,%s) appears more than once",
1283  member->number,
1284  format_type_be(member->lefttype),
1285  format_type_be(member->righttype))));
1286  else
1287  ereport(ERROR,
1288  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1289  errmsg("operator number %d for (%s,%s) appears more than once",
1290  member->number,
1291  format_type_be(member->lefttype),
1292  format_type_be(member->righttype))));
1293  }
1294  }
1295  *list = lappend(*list, member);
1296 }
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:322
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 776 of file opclasscmds.c.

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AMNAME, AlterOpFamilyStmt::amname, 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().

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

◆ AlterOpFamilyAdd()

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

Definition at line 837 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().

839 {
840  List *operators; /* OpFamilyMember list for operators */
841  List *procedures; /* OpFamilyMember list for support procs */
842  ListCell *l;
843 
844  operators = NIL;
845  procedures = NIL;
846 
847  /*
848  * Scan the "items" list to obtain additional info.
849  */
850  foreach(l, items)
851  {
853  Oid operOid;
854  Oid funcOid;
855  Oid sortfamilyOid;
857 
858  switch (item->itemtype)
859  {
861  if (item->number <= 0 || item->number > maxOpNumber)
862  ereport(ERROR,
863  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
864  errmsg("invalid operator number %d,"
865  " must be between 1 and %d",
866  item->number, maxOpNumber)));
867  if (item->name->objargs != NIL)
868  operOid = LookupOperWithArgs(item->name, false);
869  else
870  {
871  ereport(ERROR,
872  (errcode(ERRCODE_SYNTAX_ERROR),
873  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
874  operOid = InvalidOid; /* keep compiler quiet */
875  }
876 
877  if (item->order_family)
878  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
879  item->order_family,
880  false);
881  else
882  sortfamilyOid = InvalidOid;
883 
884 #ifdef NOT_USED
885  /* XXX this is unnecessary given the superuser check above */
886  /* Caller must own operator and its underlying function */
887  if (!pg_oper_ownercheck(operOid, GetUserId()))
889  get_opname(operOid));
890  funcOid = get_opcode(operOid);
891  if (!pg_proc_ownercheck(funcOid, GetUserId()))
893  get_func_name(funcOid));
894 #endif
895 
896  /* Save the info */
897  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
898  member->object = operOid;
899  member->number = item->number;
900  member->sortfamily = sortfamilyOid;
901  assignOperTypes(member, amoid, InvalidOid);
902  addFamilyMember(&operators, member, false);
903  break;
905  if (item->number <= 0 || item->number > maxProcNumber)
906  ereport(ERROR,
907  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
908  errmsg("invalid function number %d,"
909  " must be between 1 and %d",
910  item->number, maxProcNumber)));
911  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
912 #ifdef NOT_USED
913  /* XXX this is unnecessary given the superuser check above */
914  /* Caller must own function */
915  if (!pg_proc_ownercheck(funcOid, GetUserId()))
917  get_func_name(funcOid));
918 #endif
919 
920  /* Save the info */
921  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
922  member->object = funcOid;
923  member->number = item->number;
924 
925  /* allow overriding of the function's actual arg types */
926  if (item->class_args)
928  &member->lefttype, &member->righttype);
929 
930  assignProcTypes(member, amoid, InvalidOid);
931  addFamilyMember(&procedures, member, true);
932  break;
934  ereport(ERROR,
935  (errcode(ERRCODE_SYNTAX_ERROR),
936  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
937  break;
938  default:
939  elog(ERROR, "unrecognized item type: %d", item->itemtype);
940  break;
941  }
942  }
943 
944  /*
945  * Add tuples to pg_amop and pg_amproc tying in the operators and
946  * functions. Dependencies on them are inserted, too.
947  */
948  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
949  InvalidOid, operators, true);
950  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
951  InvalidOid, procedures, true);
952 
953  /* make information available to event triggers */
954  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
955  operators, procedures);
956 }
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:1067
Oid GetUserId(void)
Definition: miscinit.c:380
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4807
int errcode(int sqlerrcode)
Definition: elog.c:570
unsigned int Oid
Definition: postgres_ext.h:31
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2582
char * get_opname(Oid opno)
Definition: lsyscache.c:1117
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
#define ERROR
Definition: elog.h:43
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
#define lfirst_node(type, lc)
Definition: pg_list.h:193
ObjectWithArgs * name
Definition: parsenodes.h:2590
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1267
#define ereport(elevel, rest)
Definition: elog.h:141
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1038
void * palloc0(Size size)
Definition: mcxt.c:980
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2583
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2584
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:1424
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2160
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1133
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1306
Definition: pg_list.h:50
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4833

◆ AlterOpFamilyDrop()

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

Definition at line 962 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().

964 {
965  List *operators; /* OpFamilyMember list for operators */
966  List *procedures; /* OpFamilyMember list for support procs */
967  ListCell *l;
968 
969  operators = NIL;
970  procedures = NIL;
971 
972  /*
973  * Scan the "items" list to obtain additional info.
974  */
975  foreach(l, items)
976  {
978  Oid lefttype,
979  righttype;
981 
982  switch (item->itemtype)
983  {
985  if (item->number <= 0 || item->number > maxOpNumber)
986  ereport(ERROR,
987  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
988  errmsg("invalid operator number %d,"
989  " must be between 1 and %d",
990  item->number, maxOpNumber)));
991  processTypesSpec(item->class_args, &lefttype, &righttype);
992  /* Save the info */
993  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
994  member->number = item->number;
995  member->lefttype = lefttype;
996  member->righttype = righttype;
997  addFamilyMember(&operators, member, false);
998  break;
1000  if (item->number <= 0 || item->number > maxProcNumber)
1001  ereport(ERROR,
1002  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1003  errmsg("invalid function number %d,"
1004  " must be between 1 and %d",
1005  item->number, maxProcNumber)));
1006  processTypesSpec(item->class_args, &lefttype, &righttype);
1007  /* Save the info */
1008  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1009  member->number = item->number;
1010  member->lefttype = lefttype;
1011  member->righttype = righttype;
1012  addFamilyMember(&procedures, member, true);
1013  break;
1015  /* grammar prevents this from appearing */
1016  default:
1017  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1018  break;
1019  }
1020  }
1021 
1022  /*
1023  * Remove tuples from pg_amop and pg_amproc.
1024  */
1025  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1026  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1027 
1028  /* make information available to event triggers */
1029  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1030  operators, procedures);
1031 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:570
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1567
unsigned int Oid
Definition: postgres_ext.h:31
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2582
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1527
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:1267
#define ereport(elevel, rest)
Definition: elog.h:141
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1038
void * palloc0(Size size)
Definition: mcxt.c:980
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2583
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2584
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
Definition: pg_list.h:50

◆ assignOperTypes()

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

Definition at line 1067 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().

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

◆ assignProcTypes()

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

Definition at line 1133 of file opclasscmds.c.

References BTINRANGE_PROC, BTORDER_PROC, BTSORTSUPPORT_PROC, elog, ereport, errcode(), 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().

1134 {
1135  HeapTuple proctup;
1136  Form_pg_proc procform;
1137 
1138  /* Fetch the procedure definition */
1139  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1140  if (!HeapTupleIsValid(proctup))
1141  elog(ERROR, "cache lookup failed for function %u", member->object);
1142  procform = (Form_pg_proc) GETSTRUCT(proctup);
1143 
1144  /*
1145  * btree comparison procs must be 2-arg procs returning int4. btree
1146  * sortsupport procs must take internal and return void. btree in_range
1147  * procs must be 5-arg procs returning bool. hash support proc 1 must be
1148  * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
1149  * returning int8. Otherwise we don't know.
1150  */
1151  if (amoid == BTREE_AM_OID)
1152  {
1153  if (member->number == BTORDER_PROC)
1154  {
1155  if (procform->pronargs != 2)
1156  ereport(ERROR,
1157  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1158  errmsg("btree comparison functions must have two arguments")));
1159  if (procform->prorettype != INT4OID)
1160  ereport(ERROR,
1161  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1162  errmsg("btree comparison functions must return integer")));
1163 
1164  /*
1165  * If lefttype/righttype isn't specified, use the proc's input
1166  * types
1167  */
1168  if (!OidIsValid(member->lefttype))
1169  member->lefttype = procform->proargtypes.values[0];
1170  if (!OidIsValid(member->righttype))
1171  member->righttype = procform->proargtypes.values[1];
1172  }
1173  else if (member->number == BTSORTSUPPORT_PROC)
1174  {
1175  if (procform->pronargs != 1 ||
1176  procform->proargtypes.values[0] != INTERNALOID)
1177  ereport(ERROR,
1178  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1179  errmsg("btree sort support functions must accept type \"internal\"")));
1180  if (procform->prorettype != VOIDOID)
1181  ereport(ERROR,
1182  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1183  errmsg("btree sort support functions must return void")));
1184 
1185  /*
1186  * Can't infer lefttype/righttype from proc, so use default rule
1187  */
1188  }
1189  else if (member->number == BTINRANGE_PROC)
1190  {
1191  if (procform->pronargs != 5)
1192  ereport(ERROR,
1193  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1194  errmsg("btree in_range functions must have five arguments")));
1195  if (procform->prorettype != BOOLOID)
1196  ereport(ERROR,
1197  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1198  errmsg("btree in_range functions must return boolean")));
1199 
1200  /*
1201  * If lefttype/righttype isn't specified, use the proc's input
1202  * types (we look at the test-value and offset arguments)
1203  */
1204  if (!OidIsValid(member->lefttype))
1205  member->lefttype = procform->proargtypes.values[0];
1206  if (!OidIsValid(member->righttype))
1207  member->righttype = procform->proargtypes.values[2];
1208  }
1209  }
1210  else if (amoid == HASH_AM_OID)
1211  {
1212  if (member->number == HASHSTANDARD_PROC)
1213  {
1214  if (procform->pronargs != 1)
1215  ereport(ERROR,
1216  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1217  errmsg("hash function 1 must have one argument")));
1218  if (procform->prorettype != INT4OID)
1219  ereport(ERROR,
1220  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1221  errmsg("hash function 1 must return integer")));
1222  }
1223  else if (member->number == HASHEXTENDED_PROC)
1224  {
1225  if (procform->pronargs != 2)
1226  ereport(ERROR,
1227  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1228  errmsg("hash function 2 must have two arguments")));
1229  if (procform->prorettype != INT8OID)
1230  ereport(ERROR,
1231  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1232  errmsg("hash function 2 must return bigint")));
1233  }
1234 
1235  /*
1236  * If lefttype/righttype isn't specified, use the proc's input type
1237  */
1238  if (!OidIsValid(member->lefttype))
1239  member->lefttype = procform->proargtypes.values[0];
1240  if (!OidIsValid(member->righttype))
1241  member->righttype = procform->proargtypes.values[0];
1242  }
1243 
1244  /*
1245  * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1246  * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1247  * isn't available, so make the user specify the types.
1248  */
1249  if (!OidIsValid(member->lefttype))
1250  member->lefttype = typeoid;
1251  if (!OidIsValid(member->righttype))
1252  member->righttype = typeoid;
1253 
1254  if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1255  ereport(ERROR,
1256  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1257  errmsg("associated data types must be specified for index support function")));
1258 
1259  ReleaseSysCache(proctup);
1260 }
#define BTORDER_PROC
Definition: nbtree.h:392
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:393
int errcode(int sqlerrcode)
Definition: elog.c:570
#define HASHEXTENDED_PROC
Definition: hash.h:338
#define OidIsValid(objectId)
Definition: c.h:638
#define BTINRANGE_PROC
Definition: nbtree.h:394
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define HASHSTANDARD_PROC
Definition: hash.h:337
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226

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

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

Definition at line 731 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().

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

◆ dropOperators()

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

Definition at line 1527 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().

1529 {
1530  ListCell *l;
1531 
1532  foreach(l, operators)
1533  {
1534  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1535  Oid amopid;
1536  ObjectAddress object;
1537 
1538  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1539  ObjectIdGetDatum(opfamilyoid),
1542  Int16GetDatum(op->number));
1543  if (!OidIsValid(amopid))
1544  ereport(ERROR,
1545  (errcode(ERRCODE_UNDEFINED_OBJECT),
1546  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1547  op->number,
1548  format_type_be(op->lefttype),
1550  NameListToString(opfamilyname))));
1551 
1552  object.classId = AccessMethodOperatorRelationId;
1553  object.objectId = amopid;
1554  object.objectSubId = 0;
1555 
1556  performDeletion(&object, DROP_RESTRICT, 0);
1557  }
1558 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
#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:315
#define ereport(elevel, rest)
Definition: elog.h:141
char * NameListToString(List *names)
Definition: namespace.c:3094
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ dropProcedures()

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

Definition at line 1567 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().

1569 {
1570  ListCell *l;
1571 
1572  foreach(l, procedures)
1573  {
1574  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1575  Oid amprocid;
1576  ObjectAddress object;
1577 
1578  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1579  ObjectIdGetDatum(opfamilyoid),
1582  Int16GetDatum(op->number));
1583  if (!OidIsValid(amprocid))
1584  ereport(ERROR,
1585  (errcode(ERRCODE_UNDEFINED_OBJECT),
1586  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1587  op->number,
1588  format_type_be(op->lefttype),
1590  NameListToString(opfamilyname))));
1591 
1592  object.classId = AccessMethodProcedureRelationId;
1593  object.objectId = amprocid;
1594  object.objectSubId = 0;
1595 
1596  performDeletion(&object, DROP_RESTRICT, 0);
1597  }
1598 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
#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:315
#define ereport(elevel, rest)
Definition: elog.h:141
char * NameListToString(List *names)
Definition: namespace.c:3094
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define lfirst(lc)
Definition: pg_list.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ 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:1172
#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:1172
#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 1706 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().

1708 {
1709  /* make sure the new name doesn't exist */
1711  ObjectIdGetDatum(opcmethod),
1712  CStringGetDatum(opcname),
1713  ObjectIdGetDatum(opcnamespace)))
1714  ereport(ERROR,
1716  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1717  opcname,
1718  get_am_name(opcmethod),
1719  get_namespace_name(opcnamespace))));
1720 }
int errcode(int sqlerrcode)
Definition: elog.c:570
#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:3094
char * get_am_name(Oid amOid)
Definition: amcmds.c:216
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33

◆ IsThereOpFamilyInNamespace()

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

Definition at line 1729 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().

1731 {
1732  /* make sure the new name doesn't exist */
1734  ObjectIdGetDatum(opfmethod),
1735  CStringGetDatum(opfname),
1736  ObjectIdGetDatum(opfnamespace)))
1737  ereport(ERROR,
1739  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1740  opfname,
1741  get_am_name(opfmethod),
1742  get_namespace_name(opfnamespace))));
1743 }
int errcode(int sqlerrcode)
Definition: elog.c:570
#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:3094
char * get_am_name(Oid amOid)
Definition: amcmds.c:216
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33

◆ 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:2885
#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:570
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2801
unsigned int Oid
Definition: postgres_ext.h:31
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1792
#define OidIsValid(objectId)
Definition: c.h:638
#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:1146
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
char * NameListToString(List *names)
Definition: namespace.c:3094
#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:784
#define elog(elevel,...)
Definition: elog.h:226
#define NameStr(name)
Definition: c.h:609

◆ 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:2885
#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:570
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2801
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:638
Oid OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1875
#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:1146
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
char * NameListToString(List *names)
Definition: namespace.c:3094
#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:784
#define elog(elevel,...)
Definition: elog.h:226
#define NameStr(name)
Definition: c.h:609

◆ processTypesSpec()

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

Definition at line 1038 of file opclasscmds.c.

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

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

1039 {
1040  TypeName *typeName;
1041 
1042  Assert(args != NIL);
1043 
1044  typeName = (TypeName *) linitial(args);
1045  *lefttype = typenameTypeId(NULL, typeName);
1046 
1047  if (list_length(args) > 1)
1048  {
1049  typeName = (TypeName *) lsecond(args);
1050  *righttype = typenameTypeId(NULL, typeName);
1051  }
1052  else
1053  *righttype = *lefttype;
1054 
1055  if (list_length(args) > 2)
1056  ereport(ERROR,
1057  (errcode(ERRCODE_SYNTAX_ERROR),
1058  errmsg("one or two argument types must be specified")));
1059 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:570
#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, rest)
Definition: elog.h:141
#define Assert(condition)
Definition: c.h:732
static int list_length(const List *l)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:784
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:292

◆ RemoveAmOpEntryById()

void RemoveAmOpEntryById ( Oid  entryOid)

Definition at line 1642 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().

1643 {
1644  Relation rel;
1645  HeapTuple tup;
1646  ScanKeyData skey[1];
1647  SysScanDesc scan;
1648 
1649  ScanKeyInit(&skey[0],
1650  Anum_pg_amop_oid,
1651  BTEqualStrategyNumber, F_OIDEQ,
1652  ObjectIdGetDatum(entryOid));
1653 
1654  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1655 
1657  NULL, 1, skey);
1658 
1659  /* we expect exactly one match */
1660  tup = systable_getnext(scan);
1661  if (!HeapTupleIsValid(tup))
1662  elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1663 
1664  CatalogTupleDelete(rel, &tup->t_self);
1665 
1666  systable_endscan(scan);
1668 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#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:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#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:226
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 1671 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().

1672 {
1673  Relation rel;
1674  HeapTuple tup;
1675  ScanKeyData skey[1];
1676  SysScanDesc scan;
1677 
1678  ScanKeyInit(&skey[0],
1679  Anum_pg_amproc_oid,
1680  BTEqualStrategyNumber, F_OIDEQ,
1681  ObjectIdGetDatum(entryOid));
1682 
1683  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1684 
1686  NULL, 1, skey);
1687 
1688  /* we expect exactly one match */
1689  tup = systable_getnext(scan);
1690  if (!HeapTupleIsValid(tup))
1691  elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1692 
1693  CatalogTupleDelete(rel, &tup->t_self);
1694 
1695  systable_endscan(scan);
1697 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
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:352
#define AccessMethodProcedureOidIndexId
Definition: indexing.h:86
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#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:226
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 1623 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().

1624 {
1625  Relation rel;
1626  HeapTuple tup;
1627 
1628  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
1629 
1630  tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1631  if (!HeapTupleIsValid(tup)) /* should not happen */
1632  elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1633 
1634  CatalogTupleDelete(rel, &tup->t_self);
1635 
1636  ReleaseSysCache(tup);
1637 
1639 }
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:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ RemoveOpFamilyById()

void RemoveOpFamilyById ( Oid  opfamilyOid)

Definition at line 1604 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().

1605 {
1606  Relation rel;
1607  HeapTuple tup;
1608 
1609  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
1610 
1611  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1612  if (!HeapTupleIsValid(tup)) /* should not happen */
1613  elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1614 
1615  CatalogTupleDelete(rel, &tup->t_self);
1616 
1617  ReleaseSysCache(tup);
1618 
1620 }
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:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:226
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 1306 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().

1309 {
1310  Relation rel;
1311  Datum values[Natts_pg_amop];
1312  bool nulls[Natts_pg_amop];
1313  HeapTuple tup;
1314  Oid entryoid;
1315  ObjectAddress myself,
1316  referenced;
1317  ListCell *l;
1318 
1319  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1320 
1321  foreach(l, operators)
1322  {
1323  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1324  char oppurpose;
1325 
1326  /*
1327  * If adding to an existing family, check for conflict with an
1328  * existing pg_amop entry (just to give a nicer error message)
1329  */
1330  if (isAdd &&
1332  ObjectIdGetDatum(opfamilyoid),
1335  Int16GetDatum(op->number)))
1336  ereport(ERROR,
1338  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1339  op->number,
1340  format_type_be(op->lefttype),
1342  NameListToString(opfamilyname))));
1343 
1344  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1345 
1346  /* Create the pg_amop entry */
1347  memset(values, 0, sizeof(values));
1348  memset(nulls, false, sizeof(nulls));
1349 
1351  Anum_pg_amop_oid);
1352  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1353  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1354  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1355  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1356  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1357  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1358  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1359  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1360  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1361 
1362  tup = heap_form_tuple(rel->rd_att, values, nulls);
1363 
1364  CatalogTupleInsert(rel, tup);
1365 
1366  heap_freetuple(tup);
1367 
1368  /* Make its dependencies */
1369  myself.classId = AccessMethodOperatorRelationId;
1370  myself.objectId = entryoid;
1371  myself.objectSubId = 0;
1372 
1373  referenced.classId = OperatorRelationId;
1374  referenced.objectId = op->object;
1375  referenced.objectSubId = 0;
1376 
1377  if (OidIsValid(opclassoid))
1378  {
1379  /* if contained in an opclass, use a NORMAL dep on operator */
1380  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1381 
1382  /* ... and an INTERNAL dep on the opclass */
1383  referenced.classId = OperatorClassRelationId;
1384  referenced.objectId = opclassoid;
1385  referenced.objectSubId = 0;
1386  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1387  }
1388  else
1389  {
1390  /* if "loose" in the opfamily, use a AUTO dep on operator */
1391  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1392 
1393  /* ... and an AUTO dep on the opfamily */
1394  referenced.classId = OperatorFamilyRelationId;
1395  referenced.objectId = opfamilyoid;
1396  referenced.objectSubId = 0;
1397  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1398  }
1399 
1400  /* A search operator also needs a dep on the referenced opfamily */
1401  if (OidIsValid(op->sortfamily))
1402  {
1403  referenced.classId = OperatorFamilyRelationId;
1404  referenced.objectId = op->sortfamily;
1405  referenced.objectSubId = 0;
1406  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1407  }
1408  /* Post create hook of this access method operator */
1409  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1410  entryoid, 0);
1411  }
1412 
1414 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#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:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
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:638
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:141
char * NameListToString(List *names)
Definition: namespace.c:3094
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#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:784
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
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 1424 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().

1427 {
1428  Relation rel;
1429  Datum values[Natts_pg_amproc];
1430  bool nulls[Natts_pg_amproc];
1431  HeapTuple tup;
1432  Oid entryoid;
1433  ObjectAddress myself,
1434  referenced;
1435  ListCell *l;
1436 
1437  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1438 
1439  foreach(l, procedures)
1440  {
1441  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1442 
1443  /*
1444  * If adding to an existing family, check for conflict with an
1445  * existing pg_amproc entry (just to give a nicer error message)
1446  */
1447  if (isAdd &&
1449  ObjectIdGetDatum(opfamilyoid),
1450  ObjectIdGetDatum(proc->lefttype),
1451  ObjectIdGetDatum(proc->righttype),
1452  Int16GetDatum(proc->number)))
1453  ereport(ERROR,
1455  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1456  proc->number,
1457  format_type_be(proc->lefttype),
1458  format_type_be(proc->righttype),
1459  NameListToString(opfamilyname))));
1460 
1461  /* Create the pg_amproc entry */
1462  memset(values, 0, sizeof(values));
1463  memset(nulls, false, sizeof(nulls));
1464 
1466  Anum_pg_amproc_oid);
1467  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1468  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1469  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1470  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1471  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1472  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1473 
1474  tup = heap_form_tuple(rel->rd_att, values, nulls);
1475 
1476  CatalogTupleInsert(rel, tup);
1477 
1478  heap_freetuple(tup);
1479 
1480  /* Make its dependencies */
1481  myself.classId = AccessMethodProcedureRelationId;
1482  myself.objectId = entryoid;
1483  myself.objectSubId = 0;
1484 
1485  referenced.classId = ProcedureRelationId;
1486  referenced.objectId = proc->object;
1487  referenced.objectSubId = 0;
1488 
1489  if (OidIsValid(opclassoid))
1490  {
1491  /* if contained in an opclass, use a NORMAL dep on procedure */
1492  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1493 
1494  /* ... and an INTERNAL dep on the opclass */
1495  referenced.classId = OperatorClassRelationId;
1496  referenced.objectId = opclassoid;
1497  referenced.objectSubId = 0;
1498  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1499  }
1500  else
1501  {
1502  /* if "loose" in the opfamily, use a AUTO dep on procedure */
1503  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1504 
1505  /* ... and an AUTO dep on the opfamily */
1506  referenced.classId = OperatorFamilyRelationId;
1507  referenced.objectId = opfamilyoid;
1508  referenced.objectSubId = 0;
1509  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1510  }
1511  /* Post create hook of access method procedure */
1512  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1513  entryoid, 0);
1514  }
1515 
1517 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#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:570
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
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:638
#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
#define ereport(elevel, rest)
Definition: elog.h:141
char * NameListToString(List *names)
Definition: namespace.c:3094
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#define lfirst(lc)
Definition: pg_list.h:190
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:784
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183