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/pg_am.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
#include "commands/event_trigger.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for opclasscmds.c:

Go to the source code of this file.

Functions

static void AlterOpFamilyAdd (AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int opclassOptsProcNumber, List *items)
 
static void AlterOpFamilyDrop (AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
 
static void processTypesSpec (List *args, Oid *lefttype, Oid *righttype)
 
static void assignOperTypes (OpFamilyMember *member, Oid amoid, Oid typeoid)
 
static void assignProcTypes (OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
 
static void addFamilyMember (List **list, OpFamilyMember *member)
 
static void storeOperators (List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
 
static void storeProcedures (List *opfamilyname, Oid amoid, Oid opfamilyoid, 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 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 
)
static

Definition at line 1383 of file opclasscmds.c.

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

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

1384 {
1385  ListCell *l;
1386 
1387  foreach(l, *list)
1388  {
1389  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1390 
1391  if (old->number == member->number &&
1392  old->lefttype == member->lefttype &&
1393  old->righttype == member->righttype)
1394  {
1395  if (member->is_func)
1396  ereport(ERROR,
1397  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1398  errmsg("function number %d for (%s,%s) appears more than once",
1399  member->number,
1400  format_type_be(member->lefttype),
1401  format_type_be(member->righttype))));
1402  else
1403  ereport(ERROR,
1404  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1405  errmsg("operator number %d for (%s,%s) appears more than once",
1406  member->number,
1407  format_type_be(member->lefttype),
1408  format_type_be(member->righttype))));
1409  }
1410  }
1411  *list = lappend(*list, member);
1412 }
int number
Definition: amapi.h:84
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
Oid righttype
Definition: amapi.h:86
bool is_func
Definition: amapi.h:82
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:321
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid lefttype
Definition: amapi.h:85

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 808 of file opclasscmds.c.

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

Referenced by ProcessUtilitySlow().

809 {
810  Oid amoid, /* our AM's oid */
811  opfamilyoid; /* oid of opfamily */
812  int maxOpNumber, /* amstrategies value */
813  optsProcNumber, /* amopclassopts value */
814  maxProcNumber; /* amsupport value */
815  HeapTuple tup;
816  Form_pg_am amform;
817  IndexAmRoutine *amroutine;
818 
819  /* Get necessary info about access method */
821  if (!HeapTupleIsValid(tup))
822  ereport(ERROR,
823  (errcode(ERRCODE_UNDEFINED_OBJECT),
824  errmsg("access method \"%s\" does not exist",
825  stmt->amname)));
826 
827  amform = (Form_pg_am) GETSTRUCT(tup);
828  amoid = amform->oid;
829  amroutine = GetIndexAmRoutineByAmId(amoid, false);
830  ReleaseSysCache(tup);
831 
832  maxOpNumber = amroutine->amstrategies;
833  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
834  if (maxOpNumber <= 0)
835  maxOpNumber = SHRT_MAX;
836  maxProcNumber = amroutine->amsupport;
837  optsProcNumber = amroutine->amoptsprocnum;
838 
839  /* XXX Should we make any privilege check against the AM? */
840 
841  /* Look up the opfamily */
842  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
843 
844  /*
845  * Currently, we require superuser privileges to alter an opfamily.
846  *
847  * XXX re-enable NOT_USED code sections below if you remove this test.
848  */
849  if (!superuser())
850  ereport(ERROR,
852  errmsg("must be superuser to alter an operator family")));
853 
854  /*
855  * ADD and DROP cases need separate code from here on down.
856  */
857  if (stmt->isDrop)
858  AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
859  maxOpNumber, maxProcNumber, stmt->items);
860  else
861  AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
862  maxOpNumber, maxProcNumber, optsProcNumber,
863  stmt->items);
864 
865  return opfamilyoid;
866 }
uint16 amsupport
Definition: amapi.h:215
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:1021
#define ERRCODE_INSUFFICIENT_PRIVILEGE
#define ERROR
Definition: elog.h:43
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
#define CStringGetDatum(X)
Definition: postgres.h:578
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int opclassOptsProcNumber, List *items)
Definition: opclasscmds.c:872
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:139
uint16 amstrategies
Definition: amapi.h:213
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:821
uint16 amoptsprocnum
Definition: amapi.h:217

◆ AlterOpFamilyAdd()

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

Definition at line 872 of file opclasscmds.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, addFamilyMember(), IndexAmRoutine::amadjustmembers, assignOperTypes(), assignProcTypes(), CreateOpClassItem::class_args, elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), get_func_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetIndexAmRoutineByAmId(), GetUserId(), InvalidOid, OpFamilyMember::is_func, 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::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, OpFamilyMember::righttype, OpFamilyMember::sortfamily, storeOperators(), and storeProcedures().

Referenced by AlterOpFamily().

875 {
876  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
877  List *operators; /* OpFamilyMember list for operators */
878  List *procedures; /* OpFamilyMember list for support procs */
879  ListCell *l;
880 
881  operators = NIL;
882  procedures = NIL;
883 
884  /*
885  * Scan the "items" list to obtain additional info.
886  */
887  foreach(l, items)
888  {
890  Oid operOid;
891  Oid funcOid;
892  Oid sortfamilyOid;
894 
895  switch (item->itemtype)
896  {
898  if (item->number <= 0 || item->number > maxOpNumber)
899  ereport(ERROR,
900  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
901  errmsg("invalid operator number %d,"
902  " must be between 1 and %d",
903  item->number, maxOpNumber)));
904  if (item->name->objargs != NIL)
905  operOid = LookupOperWithArgs(item->name, false);
906  else
907  {
908  ereport(ERROR,
909  (errcode(ERRCODE_SYNTAX_ERROR),
910  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
911  operOid = InvalidOid; /* keep compiler quiet */
912  }
913 
914  if (item->order_family)
915  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
916  item->order_family,
917  false);
918  else
919  sortfamilyOid = InvalidOid;
920 
921 #ifdef NOT_USED
922  /* XXX this is unnecessary given the superuser check above */
923  /* Caller must own operator and its underlying function */
924  if (!pg_oper_ownercheck(operOid, GetUserId()))
926  get_opname(operOid));
927  funcOid = get_opcode(operOid);
928  if (!pg_proc_ownercheck(funcOid, GetUserId()))
930  get_func_name(funcOid));
931 #endif
932 
933  /* Save the info */
934  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
935  member->is_func = false;
936  member->object = operOid;
937  member->number = item->number;
938  member->sortfamily = sortfamilyOid;
939  /* We can set up dependency fields immediately */
940  /* Historically, ALTER ADD has created soft dependencies */
941  member->ref_is_hard = false;
942  member->ref_is_family = true;
943  member->refobjid = opfamilyoid;
944  assignOperTypes(member, amoid, InvalidOid);
945  addFamilyMember(&operators, member);
946  break;
948  if (item->number <= 0 || item->number > maxProcNumber)
949  ereport(ERROR,
950  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
951  errmsg("invalid function number %d,"
952  " must be between 1 and %d",
953  item->number, maxProcNumber)));
954  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
955 #ifdef NOT_USED
956  /* XXX this is unnecessary given the superuser check above */
957  /* Caller must own function */
958  if (!pg_proc_ownercheck(funcOid, GetUserId()))
960  get_func_name(funcOid));
961 #endif
962 
963  /* Save the info */
964  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
965  member->is_func = true;
966  member->object = funcOid;
967  member->number = item->number;
968  /* We can set up dependency fields immediately */
969  /* Historically, ALTER ADD has created soft dependencies */
970  member->ref_is_hard = false;
971  member->ref_is_family = true;
972  member->refobjid = opfamilyoid;
973 
974  /* allow overriding of the function's actual arg types */
975  if (item->class_args)
977  &member->lefttype, &member->righttype);
978 
979  assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
980  addFamilyMember(&procedures, member);
981  break;
983  ereport(ERROR,
984  (errcode(ERRCODE_SYNTAX_ERROR),
985  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
986  break;
987  default:
988  elog(ERROR, "unrecognized item type: %d", item->itemtype);
989  break;
990  }
991  }
992 
993  /*
994  * Let the index AM editorialize on the dependency choices. It could also
995  * do further validation on the operators and functions, if it likes.
996  */
997  if (amroutine->amadjustmembers)
998  amroutine->amadjustmembers(opfamilyoid,
999  InvalidOid, /* no specific opclass */
1000  operators,
1001  procedures);
1002 
1003  /*
1004  * Add tuples to pg_amop and pg_amproc tying in the operators and
1005  * functions. Dependencies on them are inserted, too.
1006  */
1007  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
1008  operators, true);
1009  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
1010  procedures, true);
1011 
1012  /* make information available to event triggers */
1013  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1014  operators, procedures);
1015 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:145
#define NIL
Definition: pg_list.h:65
bool ref_is_hard
Definition: amapi.h:88
static void addFamilyMember(List **list, OpFamilyMember *member)
Definition: opclasscmds.c:1383
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1128
int number
Definition: amapi.h:84
Oid GetUserId(void)
Definition: miscinit.c:476
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1420
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4739
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1527
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2611
Oid righttype
Definition: amapi.h:86
char * get_opname(Oid opno)
Definition: lsyscache.c:1227
bool is_func
Definition: amapi.h:82
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1520
#define lfirst_node(type, lc)
Definition: pg_list.h:172
ObjectWithArgs * name
Definition: parsenodes.h:2619
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1099
void * palloc0(Size size)
Definition: mcxt.c:981
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2612
amadjustmembers_function amadjustmembers
Definition: amapi.h:269
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2613
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:139
bool ref_is_family
Definition: amapi.h:89
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1194
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
Oid sortfamily
Definition: amapi.h:87
#define elog(elevel,...)
Definition: elog.h:214
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2167
Oid lefttype
Definition: amapi.h:85
Oid refobjid
Definition: amapi.h:90
Definition: pg_list.h:50
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4765

◆ AlterOpFamilyDrop()

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

Definition at line 1021 of file opclasscmds.c.

References addFamilyMember(), CreateOpClassItem::class_args, dropOperators(), dropProcedures(), elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), OpFamilyMember::is_func, 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().

1023 {
1024  List *operators; /* OpFamilyMember list for operators */
1025  List *procedures; /* OpFamilyMember list for support procs */
1026  ListCell *l;
1027 
1028  operators = NIL;
1029  procedures = NIL;
1030 
1031  /*
1032  * Scan the "items" list to obtain additional info.
1033  */
1034  foreach(l, items)
1035  {
1037  Oid lefttype,
1038  righttype;
1040 
1041  switch (item->itemtype)
1042  {
1043  case OPCLASS_ITEM_OPERATOR:
1044  if (item->number <= 0 || item->number > maxOpNumber)
1045  ereport(ERROR,
1046  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1047  errmsg("invalid operator number %d,"
1048  " must be between 1 and %d",
1049  item->number, maxOpNumber)));
1050  processTypesSpec(item->class_args, &lefttype, &righttype);
1051  /* Save the info */
1052  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1053  member->is_func = false;
1054  member->number = item->number;
1055  member->lefttype = lefttype;
1056  member->righttype = righttype;
1057  addFamilyMember(&operators, member);
1058  break;
1059  case OPCLASS_ITEM_FUNCTION:
1060  if (item->number <= 0 || item->number > maxProcNumber)
1061  ereport(ERROR,
1062  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1063  errmsg("invalid function number %d,"
1064  " must be between 1 and %d",
1065  item->number, maxProcNumber)));
1066  processTypesSpec(item->class_args, &lefttype, &righttype);
1067  /* Save the info */
1068  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1069  member->is_func = true;
1070  member->number = item->number;
1071  member->lefttype = lefttype;
1072  member->righttype = righttype;
1073  addFamilyMember(&procedures, member);
1074  break;
1076  /* grammar prevents this from appearing */
1077  default:
1078  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1079  break;
1080  }
1081  }
1082 
1083  /*
1084  * Remove tuples from pg_amop and pg_amproc.
1085  */
1086  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1087  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1088 
1089  /* make information available to event triggers */
1090  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1091  operators, procedures);
1092 }
#define NIL
Definition: pg_list.h:65
static void addFamilyMember(List **list, OpFamilyMember *member)
Definition: opclasscmds.c:1383
int number
Definition: amapi.h:84
int errcode(int sqlerrcode)
Definition: elog.c:610
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1659
unsigned int Oid
Definition: postgres_ext.h:31
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2611
Oid righttype
Definition: amapi.h:86
bool is_func
Definition: amapi.h:82
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1619
Oid member
#define ERROR
Definition: elog.h:43
#define lfirst_node(type, lc)
Definition: pg_list.h:172
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1099
void * palloc0(Size size)
Definition: mcxt.c:981
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2612
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2613
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define elog(elevel,...)
Definition: elog.h:214
Oid lefttype
Definition: amapi.h:85
Definition: pg_list.h:50

◆ assignOperTypes()

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

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

1129 {
1130  Operator optup;
1131  Form_pg_operator opform;
1132 
1133  /* Fetch the operator definition */
1134  optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1135  if (!HeapTupleIsValid(optup))
1136  elog(ERROR, "cache lookup failed for operator %u", member->object);
1137  opform = (Form_pg_operator) GETSTRUCT(optup);
1138 
1139  /*
1140  * Opfamily operators must be binary.
1141  */
1142  if (opform->oprkind != 'b')
1143  ereport(ERROR,
1144  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1145  errmsg("index operators must be binary")));
1146 
1147  if (OidIsValid(member->sortfamily))
1148  {
1149  /*
1150  * Ordering op, check index supports that. (We could perhaps also
1151  * check that the operator returns a type supported by the sortfamily,
1152  * but that seems more trouble than it's worth here. If it does not,
1153  * the operator will never be matchable to any ORDER BY clause, but no
1154  * worse consequences can ensue. Also, trying to check that would
1155  * create an ordering hazard during dump/reload: it's possible that
1156  * the family has been created but not yet populated with the required
1157  * operators.)
1158  */
1159  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
1160 
1161  if (!amroutine->amcanorderbyop)
1162  ereport(ERROR,
1163  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1164  errmsg("access method \"%s\" does not support ordering operators",
1165  get_am_name(amoid))));
1166  }
1167  else
1168  {
1169  /*
1170  * Search operators must return boolean.
1171  */
1172  if (opform->oprresult != BOOLOID)
1173  ereport(ERROR,
1174  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1175  errmsg("index search operators must return boolean")));
1176  }
1177 
1178  /*
1179  * If lefttype/righttype isn't specified, use the operator's input types
1180  */
1181  if (!OidIsValid(member->lefttype))
1182  member->lefttype = opform->oprleft;
1183  if (!OidIsValid(member->righttype))
1184  member->righttype = opform->oprright;
1185 
1186  ReleaseSysCache(optup);
1187 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
bool amcanorderbyop
Definition: amapi.h:221
int errcode(int sqlerrcode)
Definition: elog.c:610
#define OidIsValid(objectId)
Definition: c.h:652
Oid righttype
Definition: amapi.h:86
#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:192
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
Oid sortfamily
Definition: amapi.h:87
#define elog(elevel,...)
Definition: elog.h:214
Oid lefttype
Definition: amapi.h:85

◆ assignProcTypes()

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

Definition at line 1194 of file opclasscmds.c.

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

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1196 {
1197  HeapTuple proctup;
1198  Form_pg_proc procform;
1199 
1200  /* Fetch the procedure definition */
1201  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1202  if (!HeapTupleIsValid(proctup))
1203  elog(ERROR, "cache lookup failed for function %u", member->object);
1204  procform = (Form_pg_proc) GETSTRUCT(proctup);
1205 
1206  /* Check the signature of the opclass options parsing function */
1207  if (member->number == opclassOptsProcNum)
1208  {
1209  if (OidIsValid(typeoid))
1210  {
1211  if ((OidIsValid(member->lefttype) && member->lefttype != typeoid) ||
1212  (OidIsValid(member->righttype) && member->righttype != typeoid))
1213  ereport(ERROR,
1214  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1215  errmsg("associated data types for operator class options parsing functions must match opclass input type")));
1216  }
1217  else
1218  {
1219  if (member->lefttype != member->righttype)
1220  ereport(ERROR,
1221  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1222  errmsg("left and right associated data types for operator class options parsing functions must match")));
1223  }
1224 
1225  if (procform->prorettype != VOIDOID ||
1226  procform->pronargs != 1 ||
1227  procform->proargtypes.values[0] != INTERNALOID)
1228  ereport(ERROR,
1229  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1230  errmsg("invalid operator class options parsing function"),
1231  errhint("Valid signature of operator class options parsing function is %s.",
1232  "(internal) RETURNS void")));
1233  }
1234 
1235  /*
1236  * btree comparison procs must be 2-arg procs returning int4. btree
1237  * sortsupport procs must take internal and return void. btree in_range
1238  * procs must be 5-arg procs returning bool. btree equalimage procs must
1239  * take 1 arg and return bool. hash support proc 1 must be a 1-arg proc
1240  * returning int4, while proc 2 must be a 2-arg proc returning int8.
1241  * Otherwise we don't know.
1242  */
1243  else if (amoid == BTREE_AM_OID)
1244  {
1245  if (member->number == BTORDER_PROC)
1246  {
1247  if (procform->pronargs != 2)
1248  ereport(ERROR,
1249  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1250  errmsg("btree comparison functions must have two arguments")));
1251  if (procform->prorettype != INT4OID)
1252  ereport(ERROR,
1253  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1254  errmsg("btree comparison functions must return integer")));
1255 
1256  /*
1257  * If lefttype/righttype isn't specified, use the proc's input
1258  * types
1259  */
1260  if (!OidIsValid(member->lefttype))
1261  member->lefttype = procform->proargtypes.values[0];
1262  if (!OidIsValid(member->righttype))
1263  member->righttype = procform->proargtypes.values[1];
1264  }
1265  else if (member->number == BTSORTSUPPORT_PROC)
1266  {
1267  if (procform->pronargs != 1 ||
1268  procform->proargtypes.values[0] != INTERNALOID)
1269  ereport(ERROR,
1270  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1271  errmsg("btree sort support functions must accept type \"internal\"")));
1272  if (procform->prorettype != VOIDOID)
1273  ereport(ERROR,
1274  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1275  errmsg("btree sort support functions must return void")));
1276 
1277  /*
1278  * Can't infer lefttype/righttype from proc, so use default rule
1279  */
1280  }
1281  else if (member->number == BTINRANGE_PROC)
1282  {
1283  if (procform->pronargs != 5)
1284  ereport(ERROR,
1285  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1286  errmsg("btree in_range functions must have five arguments")));
1287  if (procform->prorettype != BOOLOID)
1288  ereport(ERROR,
1289  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1290  errmsg("btree in_range functions must return boolean")));
1291 
1292  /*
1293  * If lefttype/righttype isn't specified, use the proc's input
1294  * types (we look at the test-value and offset arguments)
1295  */
1296  if (!OidIsValid(member->lefttype))
1297  member->lefttype = procform->proargtypes.values[0];
1298  if (!OidIsValid(member->righttype))
1299  member->righttype = procform->proargtypes.values[2];
1300  }
1301  else if (member->number == BTEQUALIMAGE_PROC)
1302  {
1303  if (procform->pronargs != 1)
1304  ereport(ERROR,
1305  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1306  errmsg("btree equal image functions must have one argument")));
1307  if (procform->prorettype != BOOLOID)
1308  ereport(ERROR,
1309  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1310  errmsg("btree equal image functions must return boolean")));
1311 
1312  /*
1313  * pg_amproc functions are indexed by (lefttype, righttype), but
1314  * an equalimage function can only be called at CREATE INDEX time.
1315  * The same opclass opcintype OID is always used for leftype and
1316  * righttype. Providing a cross-type routine isn't sensible.
1317  * Reject cross-type ALTER OPERATOR FAMILY ... ADD FUNCTION 4
1318  * statements here.
1319  */
1320  if (member->lefttype != member->righttype)
1321  ereport(ERROR,
1322  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1323  errmsg("btree equal image functions must not be cross-type")));
1324  }
1325  }
1326  else if (amoid == HASH_AM_OID)
1327  {
1328  if (member->number == HASHSTANDARD_PROC)
1329  {
1330  if (procform->pronargs != 1)
1331  ereport(ERROR,
1332  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1333  errmsg("hash function 1 must have one argument")));
1334  if (procform->prorettype != INT4OID)
1335  ereport(ERROR,
1336  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1337  errmsg("hash function 1 must return integer")));
1338  }
1339  else if (member->number == HASHEXTENDED_PROC)
1340  {
1341  if (procform->pronargs != 2)
1342  ereport(ERROR,
1343  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1344  errmsg("hash function 2 must have two arguments")));
1345  if (procform->prorettype != INT8OID)
1346  ereport(ERROR,
1347  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1348  errmsg("hash function 2 must return bigint")));
1349  }
1350 
1351  /*
1352  * If lefttype/righttype isn't specified, use the proc's input type
1353  */
1354  if (!OidIsValid(member->lefttype))
1355  member->lefttype = procform->proargtypes.values[0];
1356  if (!OidIsValid(member->righttype))
1357  member->righttype = procform->proargtypes.values[0];
1358  }
1359 
1360  /*
1361  * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1362  * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1363  * isn't available, so make the user specify the types.
1364  */
1365  if (!OidIsValid(member->lefttype))
1366  member->lefttype = typeoid;
1367  if (!OidIsValid(member->righttype))
1368  member->righttype = typeoid;
1369 
1370  if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1371  ereport(ERROR,
1372  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1373  errmsg("associated data types must be specified for index support function")));
1374 
1375  ReleaseSysCache(proctup);
1376 }
#define BTORDER_PROC
Definition: nbtree.h:575
int errhint(const char *fmt,...)
Definition: elog.c:1068
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:578
int number
Definition: amapi.h:84
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:576
int errcode(int sqlerrcode)
Definition: elog.c:610
#define HASHEXTENDED_PROC
Definition: hash.h:354
#define OidIsValid(objectId)
Definition: c.h:652
Oid righttype
Definition: amapi.h:86
#define BTINRANGE_PROC
Definition: nbtree.h:577
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define HASHSTANDARD_PROC
Definition: hash.h:353
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
#define elog(elevel,...)
Definition: elog.h:214
Oid lefttype
Definition: amapi.h:85

◆ CreateOpFamily()

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

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

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

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

Definition at line 328 of file opclasscmds.c.

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), IndexAmRoutine::amadjustmembers, AMNAME, CreateOpClassStmt::amname, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, assignOperTypes(), assignProcTypes(), BoolGetDatum, BTEqualStrategyNumber, CatalogTupleInsert(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum, CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, ERRCODE_INSUFFICIENT_PRIVILEGE, 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, OpFamilyMember::is_func, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, 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(), OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, 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().

329 {
330  char *opcname; /* name of opclass we're creating */
331  Oid amoid, /* our AM's oid */
332  typeoid, /* indexable datatype oid */
333  storageoid, /* storage datatype oid, if any */
334  namespaceoid, /* namespace to create opclass in */
335  opfamilyoid, /* oid of containing opfamily */
336  opclassoid; /* oid of opclass we create */
337  int maxOpNumber, /* amstrategies value */
338  optsProcNumber, /* amoptsprocnum value */
339  maxProcNumber; /* amsupport value */
340  bool amstorage; /* amstorage flag */
341  List *operators; /* OpFamilyMember list for operators */
342  List *procedures; /* OpFamilyMember list for support procs */
343  ListCell *l;
344  Relation rel;
345  HeapTuple tup;
346  Form_pg_am amform;
347  IndexAmRoutine *amroutine;
348  Datum values[Natts_pg_opclass];
349  bool nulls[Natts_pg_opclass];
350  AclResult aclresult;
351  NameData opcName;
352  ObjectAddress myself,
353  referenced;
354 
355  /* Convert list of names to a name and namespace */
356  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
357  &opcname);
358 
359  /* Check we have creation rights in target namespace */
360  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
361  if (aclresult != ACLCHECK_OK)
362  aclcheck_error(aclresult, OBJECT_SCHEMA,
363  get_namespace_name(namespaceoid));
364 
365  /* Get necessary info about access method */
367  if (!HeapTupleIsValid(tup))
368  ereport(ERROR,
369  (errcode(ERRCODE_UNDEFINED_OBJECT),
370  errmsg("access method \"%s\" does not exist",
371  stmt->amname)));
372 
373  amform = (Form_pg_am) GETSTRUCT(tup);
374  amoid = amform->oid;
375  amroutine = GetIndexAmRoutineByAmId(amoid, false);
376  ReleaseSysCache(tup);
377 
378  maxOpNumber = amroutine->amstrategies;
379  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
380  if (maxOpNumber <= 0)
381  maxOpNumber = SHRT_MAX;
382  maxProcNumber = amroutine->amsupport;
383  optsProcNumber = amroutine->amoptsprocnum;
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,
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->is_func = false;
519  member->object = operOid;
520  member->number = item->number;
521  member->sortfamily = sortfamilyOid;
522  assignOperTypes(member, amoid, typeoid);
523  addFamilyMember(&operators, member);
524  break;
526  if (item->number <= 0 || item->number > maxProcNumber)
527  ereport(ERROR,
528  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
529  errmsg("invalid function number %d,"
530  " must be between 1 and %d",
531  item->number, maxProcNumber)));
532  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
533 #ifdef NOT_USED
534  /* XXX this is unnecessary given the superuser check above */
535  /* Caller must own function */
536  if (!pg_proc_ownercheck(funcOid, GetUserId()))
538  get_func_name(funcOid));
539 #endif
540  /* Save the info */
541  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
542  member->is_func = true;
543  member->object = funcOid;
544  member->number = item->number;
545 
546  /* allow overriding of the function's actual arg types */
547  if (item->class_args)
549  &member->lefttype, &member->righttype);
550 
551  assignProcTypes(member, amoid, typeoid, optsProcNumber);
552  addFamilyMember(&procedures, member);
553  break;
555  if (OidIsValid(storageoid))
556  ereport(ERROR,
557  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
558  errmsg("storage type specified more than once")));
559  storageoid = typenameTypeId(NULL, item->storedtype);
560 
561 #ifdef NOT_USED
562  /* XXX this is unnecessary given the superuser check above */
563  /* Check we have ownership of the datatype */
564  if (!pg_type_ownercheck(storageoid, GetUserId()))
566 #endif
567  break;
568  default:
569  elog(ERROR, "unrecognized item type: %d", item->itemtype);
570  break;
571  }
572  }
573 
574  /*
575  * If storagetype is specified, make sure it's legal.
576  */
577  if (OidIsValid(storageoid))
578  {
579  /* Just drop the spec if same as column datatype */
580  if (storageoid == typeoid)
581  storageoid = InvalidOid;
582  else if (!amstorage)
583  ereport(ERROR,
584  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
585  errmsg("storage type cannot be different from data type for access method \"%s\"",
586  stmt->amname)));
587  }
588 
589  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
590 
591  /*
592  * Make sure there is no existing opclass of this name (this is just to
593  * give a more friendly error message than "duplicate key").
594  */
596  ObjectIdGetDatum(amoid),
597  CStringGetDatum(opcname),
598  ObjectIdGetDatum(namespaceoid)))
599  ereport(ERROR,
601  errmsg("operator class \"%s\" for access method \"%s\" already exists",
602  opcname, stmt->amname)));
603 
604  /*
605  * If we are creating a default opclass, check there isn't one already.
606  * (Note we do not restrict this test to visible opclasses; this ensures
607  * that typcache.c can find unique solutions to its questions.)
608  */
609  if (stmt->isDefault)
610  {
611  ScanKeyData skey[1];
612  SysScanDesc scan;
613 
614  ScanKeyInit(&skey[0],
615  Anum_pg_opclass_opcmethod,
616  BTEqualStrategyNumber, F_OIDEQ,
617  ObjectIdGetDatum(amoid));
618 
620  NULL, 1, skey);
621 
622  while (HeapTupleIsValid(tup = systable_getnext(scan)))
623  {
624  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
625 
626  if (opclass->opcintype == typeoid && opclass->opcdefault)
627  ereport(ERROR,
629  errmsg("could not make operator class \"%s\" be default for type %s",
630  opcname,
631  TypeNameToString(stmt->datatype)),
632  errdetail("Operator class \"%s\" already is the default.",
633  NameStr(opclass->opcname))));
634  }
635 
636  systable_endscan(scan);
637  }
638 
639  /*
640  * Okay, let's create the pg_opclass entry.
641  */
642  memset(values, 0, sizeof(values));
643  memset(nulls, false, sizeof(nulls));
644 
645  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
646  Anum_pg_opclass_oid);
647  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
648  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
649  namestrcpy(&opcName, opcname);
650  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
651  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
652  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
653  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
654  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
655  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
656  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
657 
658  tup = heap_form_tuple(rel->rd_att, values, nulls);
659 
660  CatalogTupleInsert(rel, tup);
661 
662  heap_freetuple(tup);
663 
664  /*
665  * Now that we have the opclass OID, set up default dependency info for
666  * the pg_amop and pg_amproc entries. Historically, CREATE OPERATOR CLASS
667  * has created hard dependencies on the opclass, so that's what we use.
668  */
669  foreach(l, operators)
670  {
671  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
672 
673  op->ref_is_hard = true;
674  op->ref_is_family = false;
675  op->refobjid = opclassoid;
676  }
677  foreach(l, procedures)
678  {
679  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
680 
681  proc->ref_is_hard = true;
682  proc->ref_is_family = false;
683  proc->refobjid = opclassoid;
684  }
685 
686  /*
687  * Let the index AM editorialize on the dependency choices. It could also
688  * do further validation on the operators and functions, if it likes.
689  */
690  if (amroutine->amadjustmembers)
691  amroutine->amadjustmembers(opfamilyoid,
692  opclassoid,
693  operators,
694  procedures);
695 
696  /*
697  * Now add tuples to pg_amop and pg_amproc tying in the operators and
698  * functions. Dependencies on them are inserted, too.
699  */
700  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
701  operators, false);
702  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
703  procedures, false);
704 
705  /* let event triggers know what happened */
706  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
707 
708  /*
709  * Create dependencies for the opclass proper. Note: we do not need a
710  * dependency link to the AM, because that exists through the opfamily.
711  */
712  myself.classId = OperatorClassRelationId;
713  myself.objectId = opclassoid;
714  myself.objectSubId = 0;
715 
716  /* dependency on namespace */
717  referenced.classId = NamespaceRelationId;
718  referenced.objectId = namespaceoid;
719  referenced.objectSubId = 0;
720  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
721 
722  /* dependency on opfamily */
723  referenced.classId = OperatorFamilyRelationId;
724  referenced.objectId = opfamilyoid;
725  referenced.objectSubId = 0;
726  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
727 
728  /* dependency on indexed datatype */
729  referenced.classId = TypeRelationId;
730  referenced.objectId = typeoid;
731  referenced.objectSubId = 0;
732  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
733 
734  /* dependency on storage datatype */
735  if (OidIsValid(storageoid))
736  {
737  referenced.classId = TypeRelationId;
738  referenced.objectId = storageoid;
739  referenced.objectSubId = 0;
740  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
741  }
742 
743  /* dependency on owner */
744  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
745 
746  /* dependency on extension */
747  recordDependencyOnCurrentExtension(&myself, false);
748 
749  /* Post creation hook for new operator class */
750  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
751 
753 
754  return myself;
755 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:145
#define NIL
Definition: pg_list.h:65
bool ref_is_hard
Definition: amapi.h:88
static void addFamilyMember(List **list, OpFamilyMember *member)
Definition: opclasscmds.c:1383
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
#define NameGetDatum(X)
Definition: postgres.h:595
uint16 amsupport
Definition: amapi.h:215
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1128
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
int number
Definition: amapi.h:84
Oid GetUserId(void)
Definition: miscinit.c:476
TypeName * storedtype
Definition: parsenodes.h:2625
void namestrcpy(Name name, const char *str)
Definition: name.c:233
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2994
#define PointerGetDatum(X)
Definition: postgres.h:556
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1420
bool amstorage
Definition: amapi.h:235
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4739
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:101
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:4713
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1527
#define OidIsValid(objectId)
Definition: c.h:652
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
#define OpclassAmNameNspIndexId
Definition: indexing.h:206
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3607
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2611
Oid righttype
Definition: amapi.h:86
char * get_opname(Oid opno)
Definition: lsyscache.c:1227
bool is_func
Definition: amapi.h:82
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ERRCODE_INSUFFICIENT_PRIVILEGE
#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:1520
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Definition: c.h:617
TypeName * datatype
Definition: parsenodes.h:2606
ObjectWithArgs * name
Definition: parsenodes.h:2619
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:954
#define CStringGetDatum(X)
Definition: postgres.h:578
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:243
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1099
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void * palloc0(Size size)
Definition: mcxt.c:981
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1164
TupleDesc rd_att
Definition: rel.h:110
#define OpclassOidIndexId
Definition: indexing.h:208
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1202
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2612
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
amadjustmembers_function amadjustmembers
Definition: amapi.h:269
#define lfirst(lc)
Definition: pg_list.h:169
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:180
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2613
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:139
bool ref_is_family
Definition: amapi.h:89
uint16 amstrategies
Definition: amapi.h:213
static Datum values[MAXATTR]
Definition: bootstrap.c:165
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1194
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
uint16 amoptsprocnum
Definition: amapi.h:217
Oid sortfamily
Definition: amapi.h:87
#define elog(elevel,...)
Definition: elog.h:214
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2167
Oid lefttype
Definition: amapi.h:85
#define NameStr(name)
Definition: c.h:623
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Oid refobjid
Definition: amapi.h:90
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:32
Definition: pg_list.h:50
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4765
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

Definition at line 763 of file opclasscmds.c.

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

Referenced by ProcessUtilitySlow().

764 {
765  char *opfname; /* name of opfamily we're creating */
766  Oid amoid, /* our AM's oid */
767  namespaceoid; /* namespace to create opfamily in */
768  AclResult aclresult;
769 
770  /* Convert list of names to a name and namespace */
771  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
772  &opfname);
773 
774  /* Check we have creation rights in target namespace */
775  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
776  if (aclresult != ACLCHECK_OK)
777  aclcheck_error(aclresult, OBJECT_SCHEMA,
778  get_namespace_name(namespaceoid));
779 
780  /* Get access method OID, throwing an error if it doesn't exist. */
781  amoid = get_index_am_oid(stmt->amname, false);
782 
783  /* XXX Should we make any privilege check against the AM? */
784 
785  /*
786  * Currently, we require superuser privileges to create an opfamily. See
787  * comments in DefineOpClass.
788  */
789  if (!superuser())
790  ereport(ERROR,
792  errmsg("must be superuser to create an operator family")));
793 
794  /* Insert pg_opfamily catalog entry */
795  return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
796 }
Oid GetUserId(void)
Definition: miscinit.c:476
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2994
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERRCODE_INSUFFICIENT_PRIVILEGE
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:163
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:243
AclResult
Definition: acl.h:177
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:821

◆ dropOperators()

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

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

1621 {
1622  ListCell *l;
1623 
1624  foreach(l, operators)
1625  {
1626  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1627  Oid amopid;
1628  ObjectAddress object;
1629 
1630  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1631  ObjectIdGetDatum(opfamilyoid),
1634  Int16GetDatum(op->number));
1635  if (!OidIsValid(amopid))
1636  ereport(ERROR,
1637  (errcode(ERRCODE_UNDEFINED_OBJECT),
1638  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1639  op->number,
1640  format_type_be(op->lefttype),
1642  NameListToString(opfamilyname))));
1643 
1644  object.classId = AccessMethodOperatorRelationId;
1645  object.objectId = amopid;
1646  object.objectSubId = 0;
1647 
1648  performDeletion(&object, DROP_RESTRICT, 0);
1649  }
1650 }
int number
Definition: amapi.h:84
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
Oid righttype
Definition: amapi.h:86
#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:312
char * NameListToString(List *names)
Definition: namespace.c:3101
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid lefttype
Definition: amapi.h:85

◆ dropProcedures()

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

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

1661 {
1662  ListCell *l;
1663 
1664  foreach(l, procedures)
1665  {
1666  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1667  Oid amprocid;
1668  ObjectAddress object;
1669 
1670  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1671  ObjectIdGetDatum(opfamilyoid),
1674  Int16GetDatum(op->number));
1675  if (!OidIsValid(amprocid))
1676  ereport(ERROR,
1677  (errcode(ERRCODE_UNDEFINED_OBJECT),
1678  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1679  op->number,
1680  format_type_be(op->lefttype),
1682  NameListToString(opfamilyname))));
1683 
1684  object.classId = AccessMethodProcedureRelationId;
1685  object.objectId = amprocid;
1686  object.objectSubId = 0;
1687 
1688  performDeletion(&object, DROP_RESTRICT, 0);
1689  }
1690 }
int number
Definition: amapi.h:84
#define Int16GetDatum(X)
Definition: postgres.h:451
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:652
Oid righttype
Definition: amapi.h:86
#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:312
char * NameListToString(List *names)
Definition: namespace.c:3101
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid lefttype
Definition: amapi.h:85

◆ get_opclass_oid()

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

Definition at line 220 of file opclasscmds.c.

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

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

221 {
222  HeapTuple htup;
223  Form_pg_opclass opcform;
224  Oid opcID;
225 
226  htup = OpClassCacheLookup(amID, opclassname, missing_ok);
227  if (!HeapTupleIsValid(htup))
228  return InvalidOid;
229  opcform = (Form_pg_opclass) GETSTRUCT(htup);
230  opcID = opcform->oid;
231  ReleaseSysCache(htup);
232 
233  return opcID;
234 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:162
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 139 of file opclasscmds.c.

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

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

140 {
141  HeapTuple htup;
142  Form_pg_opfamily opfamform;
143  Oid opfID;
144 
145  htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
146  if (!HeapTupleIsValid(htup))
147  return InvalidOid;
148  opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
149  opfID = opfamform->oid;
150  ReleaseSysCache(htup);
151 
152  return opfID;
153 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:81
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 1699 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().

1701 {
1702  /* make sure the new name doesn't exist */
1704  ObjectIdGetDatum(opcmethod),
1705  CStringGetDatum(opcname),
1706  ObjectIdGetDatum(opcnamespace)))
1707  ereport(ERROR,
1709  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1710  opcname,
1711  get_am_name(opcmethod),
1712  get_namespace_name(opcnamespace))));
1713 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ IsThereOpFamilyInNamespace()

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

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

1724 {
1725  /* make sure the new name doesn't exist */
1727  ObjectIdGetDatum(opfmethod),
1728  CStringGetDatum(opfname),
1729  ObjectIdGetDatum(opfnamespace)))
1730  ereport(ERROR,
1732  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1733  opfname,
1734  get_am_name(opfmethod),
1735  get_namespace_name(opfnamespace))));
1736 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:821
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32

◆ OpClassCacheLookup()

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

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

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

◆ OpFamilyCacheLookup()

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

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

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

◆ processTypesSpec()

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

Definition at line 1099 of file opclasscmds.c.

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

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

1100 {
1101  TypeName *typeName;
1102 
1103  Assert(args != NIL);
1104 
1105  typeName = (TypeName *) linitial(args);
1106  *lefttype = typenameTypeId(NULL, typeName);
1107 
1108  if (list_length(args) > 1)
1109  {
1110  typeName = (TypeName *) lsecond(args);
1111  *righttype = typenameTypeId(NULL, typeName);
1112  }
1113  else
1114  *righttype = *lefttype;
1115 
1116  if (list_length(args) > 2)
1117  ereport(ERROR,
1118  (errcode(ERRCODE_SYNTAX_ERROR),
1119  errmsg("one or two argument types must be specified")));
1120 }
#define NIL
Definition: pg_list.h:65
int errcode(int sqlerrcode)
Definition: elog.c:610
#define lsecond(l)
Definition: pg_list.h:179
#define linitial(l)
Definition: pg_list.h:174
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:746
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ storeOperators()

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

Definition at line 1420 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::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, OpFamilyMember::sortfamily, table_close(), table_open(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1422 {
1423  Relation rel;
1424  Datum values[Natts_pg_amop];
1425  bool nulls[Natts_pg_amop];
1426  HeapTuple tup;
1427  Oid entryoid;
1428  ObjectAddress myself,
1429  referenced;
1430  ListCell *l;
1431 
1432  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1433 
1434  foreach(l, operators)
1435  {
1436  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1437  char oppurpose;
1438 
1439  /*
1440  * If adding to an existing family, check for conflict with an
1441  * existing pg_amop entry (just to give a nicer error message)
1442  */
1443  if (isAdd &&
1445  ObjectIdGetDatum(opfamilyoid),
1448  Int16GetDatum(op->number)))
1449  ereport(ERROR,
1451  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1452  op->number,
1453  format_type_be(op->lefttype),
1455  NameListToString(opfamilyname))));
1456 
1457  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1458 
1459  /* Create the pg_amop entry */
1460  memset(values, 0, sizeof(values));
1461  memset(nulls, false, sizeof(nulls));
1462 
1464  Anum_pg_amop_oid);
1465  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1466  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1467  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1468  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1469  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1470  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1471  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1472  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1473  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1474 
1475  tup = heap_form_tuple(rel->rd_att, values, nulls);
1476 
1477  CatalogTupleInsert(rel, tup);
1478 
1479  heap_freetuple(tup);
1480 
1481  /* Make its dependencies */
1482  myself.classId = AccessMethodOperatorRelationId;
1483  myself.objectId = entryoid;
1484  myself.objectSubId = 0;
1485 
1486  referenced.classId = OperatorRelationId;
1487  referenced.objectId = op->object;
1488  referenced.objectSubId = 0;
1489 
1490  /* see comments in amapi.h about dependency strength */
1491  recordDependencyOn(&myself, &referenced,
1493 
1494  referenced.classId = op->ref_is_family ? OperatorFamilyRelationId :
1495  OperatorClassRelationId;
1496  referenced.objectId = op->refobjid;
1497  referenced.objectSubId = 0;
1498 
1499  recordDependencyOn(&myself, &referenced,
1501 
1502  /* A search operator also needs a dep on the referenced opfamily */
1503  if (OidIsValid(op->sortfamily))
1504  {
1505  referenced.classId = OperatorFamilyRelationId;
1506  referenced.objectId = op->sortfamily;
1507  referenced.objectSubId = 0;
1508 
1509  recordDependencyOn(&myself, &referenced,
1511  }
1512 
1513  /* Post create hook of this access method operator */
1514  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1515  entryoid, 0);
1516  }
1517 
1519 }
bool ref_is_hard
Definition: amapi.h:88
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
int number
Definition: amapi.h:84
#define Int16GetDatum(X)
Definition: postgres.h:451
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:189
#define AccessMethodOperatorOidIndexId
Definition: indexing.h:92
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
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:652
Oid righttype
Definition: amapi.h:86
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
char * NameListToString(List *names)
Definition: namespace.c:3101
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:169
bool ref_is_family
Definition: amapi.h:89
#define CharGetDatum(X)
Definition: postgres.h:416
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
Oid sortfamily
Definition: amapi.h:87
Oid lefttype
Definition: amapi.h:85
Oid refobjid
Definition: amapi.h:90
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221

◆ storeProcedures()

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

Definition at line 1527 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, RelationData::rd_att, recordDependencyOn(), OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, OpFamilyMember::righttype, RowExclusiveLock, SearchSysCacheExists4, table_close(), table_open(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

1529 {
1530  Relation rel;
1531  Datum values[Natts_pg_amproc];
1532  bool nulls[Natts_pg_amproc];
1533  HeapTuple tup;
1534  Oid entryoid;
1535  ObjectAddress myself,
1536  referenced;
1537  ListCell *l;
1538 
1539  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1540 
1541  foreach(l, procedures)
1542  {
1543  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1544 
1545  /*
1546  * If adding to an existing family, check for conflict with an
1547  * existing pg_amproc entry (just to give a nicer error message)
1548  */
1549  if (isAdd &&
1551  ObjectIdGetDatum(opfamilyoid),
1552  ObjectIdGetDatum(proc->lefttype),
1553  ObjectIdGetDatum(proc->righttype),
1554  Int16GetDatum(proc->number)))
1555  ereport(ERROR,
1557  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1558  proc->number,
1559  format_type_be(proc->lefttype),
1560  format_type_be(proc->righttype),
1561  NameListToString(opfamilyname))));
1562 
1563  /* Create the pg_amproc entry */
1564  memset(values, 0, sizeof(values));
1565  memset(nulls, false, sizeof(nulls));
1566 
1568  Anum_pg_amproc_oid);
1569  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1570  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1571  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1572  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1573  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1574  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1575 
1576  tup = heap_form_tuple(rel->rd_att, values, nulls);
1577 
1578  CatalogTupleInsert(rel, tup);
1579 
1580  heap_freetuple(tup);
1581 
1582  /* Make its dependencies */
1583  myself.classId = AccessMethodProcedureRelationId;
1584  myself.objectId = entryoid;
1585  myself.objectSubId = 0;
1586 
1587  referenced.classId = ProcedureRelationId;
1588  referenced.objectId = proc->object;
1589  referenced.objectSubId = 0;
1590 
1591  /* see comments in amapi.h about dependency strength */
1592  recordDependencyOn(&myself, &referenced,
1594 
1595  referenced.classId = proc->ref_is_family ? OperatorFamilyRelationId :
1596  OperatorClassRelationId;
1597  referenced.objectId = proc->refobjid;
1598  referenced.objectSubId = 0;
1599 
1600  recordDependencyOn(&myself, &referenced,
1602 
1603  /* Post create hook of access method procedure */
1604  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1605  entryoid, 0);
1606  }
1607 
1609 }
bool ref_is_hard
Definition: amapi.h:88
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
int number
Definition: amapi.h:84
#define Int16GetDatum(X)
Definition: postgres.h:451
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:189
int errcode(int sqlerrcode)
Definition: elog.c:610
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
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 AccessMethodProcedureOidIndexId
Definition: indexing.h:97
Oid righttype
Definition: amapi.h:86
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define RowExclusiveLock
Definition: lockdefs.h:38
char * NameListToString(List *names)
Definition: namespace.c:3101
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define ereport(elevel,...)
Definition: elog.h:144
#define lfirst(lc)
Definition: pg_list.h:169
bool ref_is_family
Definition: amapi.h:89
static Datum values[MAXATTR]
Definition: bootstrap.c:165
int errmsg(const char *fmt,...)
Definition: elog.c:821
Oid object
Definition: amapi.h:83
Oid lefttype
Definition: amapi.h:85
Oid refobjid
Definition: amapi.h:90
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221