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

Go to the source code of this file.

Functions

static void AlterOpFamilyAdd (AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, 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 1266 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().

1267 {
1268  ListCell *l;
1269 
1270  foreach(l, *list)
1271  {
1272  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1273 
1274  if (old->number == member->number &&
1275  old->lefttype == member->lefttype &&
1276  old->righttype == member->righttype)
1277  {
1278  if (isProc)
1279  ereport(ERROR,
1280  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1281  errmsg("function number %d for (%s,%s) appears more than once",
1282  member->number,
1283  format_type_be(member->lefttype),
1284  format_type_be(member->righttype))));
1285  else
1286  ereport(ERROR,
1287  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1288  errmsg("operator number %d for (%s,%s) appears more than once",
1289  member->number,
1290  format_type_be(member->lefttype),
1291  format_type_be(member->righttype))));
1292  }
1293  }
1294  *list = lappend(*list, member);
1295 }
int errcode(int sqlerrcode)
Definition: elog.c:608
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:822

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

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

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

◆ AlterOpFamilyAdd()

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

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

838 {
839  List *operators; /* OpFamilyMember list for operators */
840  List *procedures; /* OpFamilyMember list for support procs */
841  ListCell *l;
842 
843  operators = NIL;
844  procedures = NIL;
845 
846  /*
847  * Scan the "items" list to obtain additional info.
848  */
849  foreach(l, items)
850  {
852  Oid operOid;
853  Oid funcOid;
854  Oid sortfamilyOid;
856 
857  switch (item->itemtype)
858  {
860  if (item->number <= 0 || item->number > maxOpNumber)
861  ereport(ERROR,
862  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
863  errmsg("invalid operator number %d,"
864  " must be between 1 and %d",
865  item->number, maxOpNumber)));
866  if (item->name->objargs != NIL)
867  operOid = LookupOperWithArgs(item->name, false);
868  else
869  {
870  ereport(ERROR,
871  (errcode(ERRCODE_SYNTAX_ERROR),
872  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
873  operOid = InvalidOid; /* keep compiler quiet */
874  }
875 
876  if (item->order_family)
877  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
878  item->order_family,
879  false);
880  else
881  sortfamilyOid = InvalidOid;
882 
883 #ifdef NOT_USED
884  /* XXX this is unnecessary given the superuser check above */
885  /* Caller must own operator and its underlying function */
886  if (!pg_oper_ownercheck(operOid, GetUserId()))
888  get_opname(operOid));
889  funcOid = get_opcode(operOid);
890  if (!pg_proc_ownercheck(funcOid, GetUserId()))
892  get_func_name(funcOid));
893 #endif
894 
895  /* Save the info */
896  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
897  member->object = operOid;
898  member->number = item->number;
899  member->sortfamily = sortfamilyOid;
900  assignOperTypes(member, amoid, InvalidOid);
901  addFamilyMember(&operators, member, false);
902  break;
904  if (item->number <= 0 || item->number > maxProcNumber)
905  ereport(ERROR,
906  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
907  errmsg("invalid function number %d,"
908  " must be between 1 and %d",
909  item->number, maxProcNumber)));
910  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
911 #ifdef NOT_USED
912  /* XXX this is unnecessary given the superuser check above */
913  /* Caller must own function */
914  if (!pg_proc_ownercheck(funcOid, GetUserId()))
916  get_func_name(funcOid));
917 #endif
918 
919  /* Save the info */
920  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
921  member->object = funcOid;
922  member->number = item->number;
923 
924  /* allow overriding of the function's actual arg types */
925  if (item->class_args)
927  &member->lefttype, &member->righttype);
928 
929  assignProcTypes(member, amoid, InvalidOid);
930  addFamilyMember(&procedures, member, true);
931  break;
933  ereport(ERROR,
934  (errcode(ERRCODE_SYNTAX_ERROR),
935  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
936  break;
937  default:
938  elog(ERROR, "unrecognized item type: %d", item->itemtype);
939  break;
940  }
941  }
942 
943  /*
944  * Add tuples to pg_amop and pg_amproc tying in the operators and
945  * functions. Dependencies on them are inserted, too.
946  */
947  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
948  InvalidOid, operators, true);
949  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
950  InvalidOid, procedures, true);
951 
952  /* make information available to event triggers */
953  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
954  operators, procedures);
955 }
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:1066
Oid GetUserId(void)
Definition: miscinit.c:380
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4805
int errcode(int sqlerrcode)
Definition: elog.c:608
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:3352
#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:1266
#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:1037
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:141
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1423
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2161
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1132
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1305
Definition: pg_list.h:50
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4831

◆ AlterOpFamilyDrop()

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

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

963 {
964  List *operators; /* OpFamilyMember list for operators */
965  List *procedures; /* OpFamilyMember list for support procs */
966  ListCell *l;
967 
968  operators = NIL;
969  procedures = NIL;
970 
971  /*
972  * Scan the "items" list to obtain additional info.
973  */
974  foreach(l, items)
975  {
977  Oid lefttype,
978  righttype;
980 
981  switch (item->itemtype)
982  {
984  if (item->number <= 0 || item->number > maxOpNumber)
985  ereport(ERROR,
986  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
987  errmsg("invalid operator number %d,"
988  " must be between 1 and %d",
989  item->number, maxOpNumber)));
990  processTypesSpec(item->class_args, &lefttype, &righttype);
991  /* Save the info */
992  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
993  member->number = item->number;
994  member->lefttype = lefttype;
995  member->righttype = righttype;
996  addFamilyMember(&operators, member, false);
997  break;
999  if (item->number <= 0 || item->number > maxProcNumber)
1000  ereport(ERROR,
1001  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1002  errmsg("invalid function number %d,"
1003  " must be between 1 and %d",
1004  item->number, maxProcNumber)));
1005  processTypesSpec(item->class_args, &lefttype, &righttype);
1006  /* Save the info */
1007  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1008  member->number = item->number;
1009  member->lefttype = lefttype;
1010  member->righttype = righttype;
1011  addFamilyMember(&procedures, member, true);
1012  break;
1014  /* grammar prevents this from appearing */
1015  default:
1016  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1017  break;
1018  }
1019  }
1020 
1021  /*
1022  * Remove tuples from pg_amop and pg_amproc.
1023  */
1024  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1025  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1026 
1027  /* make information available to event triggers */
1028  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1029  operators, procedures);
1030 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:608
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1566
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:1526
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:1266
#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:1037
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:822
#define elog(elevel,...)
Definition: elog.h:228
Definition: pg_list.h:50

◆ assignOperTypes()

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

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

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

◆ assignProcTypes()

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

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

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

◆ CreateOpFamily()

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

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

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

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

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

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

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

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

731 {
732  char *opfname; /* name of opfamily we're creating */
733  Oid amoid, /* our AM's oid */
734  namespaceoid; /* namespace to create opfamily in */
735  AclResult aclresult;
736 
737  /* Convert list of names to a name and namespace */
738  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
739  &opfname);
740 
741  /* Check we have creation rights in target namespace */
742  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
743  if (aclresult != ACLCHECK_OK)
744  aclcheck_error(aclresult, OBJECT_SCHEMA,
745  get_namespace_name(namespaceoid));
746 
747  /* Get access method OID, throwing an error if it doesn't exist. */
748  amoid = get_index_am_oid(stmt->amname, false);
749 
750  /* XXX Should we make any privilege check against the AM? */
751 
752  /*
753  * Currently, we require superuser privileges to create an opfamily. See
754  * comments in DefineOpClass.
755  */
756  if (!superuser())
757  ereport(ERROR,
758  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
759  errmsg("must be superuser to create an operator family")));
760 
761  /* Insert pg_opfamily catalog entry */
762  return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
763 }
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:608
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4691
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#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:245
AclResult
Definition: acl.h:177
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ dropOperators()

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

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

1528 {
1529  ListCell *l;
1530 
1531  foreach(l, operators)
1532  {
1533  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1534  Oid amopid;
1535  ObjectAddress object;
1536 
1537  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1538  ObjectIdGetDatum(opfamilyoid),
1541  Int16GetDatum(op->number));
1542  if (!OidIsValid(amopid))
1543  ereport(ERROR,
1544  (errcode(ERRCODE_UNDEFINED_OBJECT),
1545  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1546  op->number,
1547  format_type_be(op->lefttype),
1549  NameListToString(opfamilyname))));
1550 
1551  object.classId = AccessMethodOperatorRelationId;
1552  object.objectId = amopid;
1553  object.objectSubId = 0;
1554 
1555  performDeletion(&object, DROP_RESTRICT, 0);
1556  }
1557 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:608
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:645
#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:822

◆ dropProcedures()

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

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

1568 {
1569  ListCell *l;
1570 
1571  foreach(l, procedures)
1572  {
1573  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1574  Oid amprocid;
1575  ObjectAddress object;
1576 
1577  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1578  ObjectIdGetDatum(opfamilyoid),
1581  Int16GetDatum(op->number));
1582  if (!OidIsValid(amprocid))
1583  ereport(ERROR,
1584  (errcode(ERRCODE_UNDEFINED_OBJECT),
1585  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1586  op->number,
1587  format_type_be(op->lefttype),
1589  NameListToString(opfamilyname))));
1590 
1591  object.classId = AccessMethodProcedureRelationId;
1592  object.objectId = amprocid;
1593  object.objectSubId = 0;
1594 
1595  performDeletion(&object, DROP_RESTRICT, 0);
1596  }
1597 }
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:608
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:645
#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:822

◆ get_opclass_oid()

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

Definition at line 222 of file opclasscmds.c.

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

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

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

◆ get_opfamily_oid()

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

Definition at line 141 of file opclasscmds.c.

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

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

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

◆ IsThereOpClassInNamespace()

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

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

1707 {
1708  /* make sure the new name doesn't exist */
1710  ObjectIdGetDatum(opcmethod),
1711  CStringGetDatum(opcname),
1712  ObjectIdGetDatum(opcnamespace)))
1713  ereport(ERROR,
1715  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1716  opcname,
1717  get_am_name(opcmethod),
1718  get_namespace_name(opcnamespace))));
1719 }
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:822
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ IsThereOpFamilyInNamespace()

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

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

1730 {
1731  /* make sure the new name doesn't exist */
1733  ObjectIdGetDatum(opfmethod),
1734  CStringGetDatum(opfname),
1735  ObjectIdGetDatum(opfnamespace)))
1736  ereport(ERROR,
1738  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1739  opfname,
1740  get_am_name(opfmethod),
1741  get_namespace_name(opfnamespace))));
1742 }
int errcode(int sqlerrcode)
Definition: elog.c:608
#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:822
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ OpClassCacheLookup()

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

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

165 {
166  char *schemaname;
167  char *opcname;
168  HeapTuple htup;
169 
170  /* deconstruct the name list */
171  DeconstructQualifiedName(opclassname, &schemaname, &opcname);
172 
173  if (schemaname)
174  {
175  /* Look in specific schema only */
176  Oid namespaceId;
177 
178  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
179  if (!OidIsValid(namespaceId))
180  htup = NULL;
181  else
183  ObjectIdGetDatum(amID),
184  PointerGetDatum(opcname),
185  ObjectIdGetDatum(namespaceId));
186  }
187  else
188  {
189  /* Unqualified opclass name, so search the search path */
190  Oid opcID = OpclassnameGetOpcid(amID, opcname);
191 
192  if (!OidIsValid(opcID))
193  htup = NULL;
194  else
195  htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
196  }
197 
198  if (!HeapTupleIsValid(htup) && !missing_ok)
199  {
200  HeapTuple amtup;
201 
202  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
203  if (!HeapTupleIsValid(amtup))
204  elog(ERROR, "cache lookup failed for access method %u", amID);
205  ereport(ERROR,
206  (errcode(ERRCODE_UNDEFINED_OBJECT),
207  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
208  NameListToString(opclassname),
209  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
210  }
211 
212  return htup;
213 }
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:608
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:645
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
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:822
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616

◆ OpFamilyCacheLookup()

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

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

84 {
85  char *schemaname;
86  char *opfname;
87  HeapTuple htup;
88 
89  /* deconstruct the name list */
90  DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
91 
92  if (schemaname)
93  {
94  /* Look in specific schema only */
95  Oid namespaceId;
96 
97  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
98  if (!OidIsValid(namespaceId))
99  htup = NULL;
100  else
102  ObjectIdGetDatum(amID),
103  PointerGetDatum(opfname),
104  ObjectIdGetDatum(namespaceId));
105  }
106  else
107  {
108  /* Unqualified opfamily name, so search the search path */
109  Oid opfID = OpfamilynameGetOpfid(amID, opfname);
110 
111  if (!OidIsValid(opfID))
112  htup = NULL;
113  else
115  }
116 
117  if (!HeapTupleIsValid(htup) && !missing_ok)
118  {
119  HeapTuple amtup;
120 
121  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
122  if (!HeapTupleIsValid(amtup))
123  elog(ERROR, "cache lookup failed for access method %u", amID);
124  ereport(ERROR,
125  (errcode(ERRCODE_UNDEFINED_OBJECT),
126  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
127  NameListToString(opfamilyname),
128  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
129  }
130 
131  return htup;
132 }
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:608
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:645
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:1138
#define ereport(elevel, rest)
Definition: elog.h:141
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
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:822
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616

◆ processTypesSpec()

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

Definition at line 1037 of file opclasscmds.c.

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

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

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

◆ RemoveAmOpEntryById()

void RemoveAmOpEntryById ( Oid  entryOid)

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

1642 {
1643  Relation rel;
1644  HeapTuple tup;
1645  ScanKeyData skey[1];
1646  SysScanDesc scan;
1647 
1648  ScanKeyInit(&skey[0],
1649  Anum_pg_amop_oid,
1650  BTEqualStrategyNumber, F_OIDEQ,
1651  ObjectIdGetDatum(entryOid));
1652 
1653  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1654 
1656  NULL, 1, skey);
1657 
1658  /* we expect exactly one match */
1659  tup = systable_getnext(scan);
1660  if (!HeapTupleIsValid(tup))
1661  elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1662 
1663  CatalogTupleDelete(rel, &tup->t_self);
1664 
1665  systable_endscan(scan);
1667 }
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:228
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 1670 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().

1671 {
1672  Relation rel;
1673  HeapTuple tup;
1674  ScanKeyData skey[1];
1675  SysScanDesc scan;
1676 
1677  ScanKeyInit(&skey[0],
1678  Anum_pg_amproc_oid,
1679  BTEqualStrategyNumber, F_OIDEQ,
1680  ObjectIdGetDatum(entryOid));
1681 
1682  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1683 
1685  NULL, 1, skey);
1686 
1687  /* we expect exactly one match */
1688  tup = systable_getnext(scan);
1689  if (!HeapTupleIsValid(tup))
1690  elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1691 
1692  CatalogTupleDelete(rel, &tup->t_self);
1693 
1694  systable_endscan(scan);
1696 }
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:228
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 1622 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().

1623 {
1624  Relation rel;
1625  HeapTuple tup;
1626 
1627  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
1628 
1629  tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1630  if (!HeapTupleIsValid(tup)) /* should not happen */
1631  elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1632 
1633  CatalogTupleDelete(rel, &tup->t_self);
1634 
1635  ReleaseSysCache(tup);
1636 
1638 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:228
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ RemoveOpFamilyById()

void RemoveOpFamilyById ( Oid  opfamilyOid)

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

1604 {
1605  Relation rel;
1606  HeapTuple tup;
1607 
1608  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
1609 
1610  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1611  if (!HeapTupleIsValid(tup)) /* should not happen */
1612  elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1613 
1614  CatalogTupleDelete(rel, &tup->t_self);
1615 
1616  ReleaseSysCache(tup);
1617 
1619 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define elog(elevel,...)
Definition: elog.h:228
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 1305 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().

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

◆ storeProcedures()

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

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

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