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 optsProcNumber, 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 (CreateOpFamilyStmt *stmt, 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 1392 of file opclasscmds.c.

1393 {
1394  ListCell *l;
1395 
1396  foreach(l, *list)
1397  {
1398  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1399 
1400  if (old->number == member->number &&
1401  old->lefttype == member->lefttype &&
1402  old->righttype == member->righttype)
1403  {
1404  if (member->is_func)
1405  ereport(ERROR,
1406  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1407  errmsg("function number %d for (%s,%s) appears more than once",
1408  member->number,
1409  format_type_be(member->lefttype),
1410  format_type_be(member->righttype))));
1411  else
1412  ereport(ERROR,
1413  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1414  errmsg("operator number %d for (%s,%s) appears more than once",
1415  member->number,
1416  format_type_be(member->lefttype),
1417  format_type_be(member->righttype))));
1418  }
1419  }
1420  *list = lappend(*list, member);
1421 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
List * lappend(List *list, void *datum)
Definition: list.c:338
#define lfirst(lc)
Definition: pg_list.h:170
Oid lefttype
Definition: amapi.h:85
Oid righttype
Definition: amapi.h:86
int number
Definition: amapi.h:84
bool is_func
Definition: amapi.h:82

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

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

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 817 of file opclasscmds.c.

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

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

Referenced by ProcessUtilitySlow().

◆ AlterOpFamilyAdd()

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

Definition at line 881 of file opclasscmds.c.

884 {
885  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
886  List *operators; /* OpFamilyMember list for operators */
887  List *procedures; /* OpFamilyMember list for support procs */
888  ListCell *l;
889 
890  operators = NIL;
891  procedures = NIL;
892 
893  /*
894  * Scan the "items" list to obtain additional info.
895  */
896  foreach(l, items)
897  {
899  Oid operOid;
900  Oid funcOid;
901  Oid sortfamilyOid;
902  OpFamilyMember *member;
903 
904  switch (item->itemtype)
905  {
907  if (item->number <= 0 || item->number > maxOpNumber)
908  ereport(ERROR,
909  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
910  errmsg("invalid operator number %d,"
911  " must be between 1 and %d",
912  item->number, maxOpNumber)));
913  if (item->name->objargs != NIL)
914  operOid = LookupOperWithArgs(item->name, false);
915  else
916  {
917  ereport(ERROR,
918  (errcode(ERRCODE_SYNTAX_ERROR),
919  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
920  operOid = InvalidOid; /* keep compiler quiet */
921  }
922 
923  if (item->order_family)
924  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
925  item->order_family,
926  false);
927  else
928  sortfamilyOid = InvalidOid;
929 
930 #ifdef NOT_USED
931  /* XXX this is unnecessary given the superuser check above */
932  /* Caller must own operator and its underlying function */
933  if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
935  get_opname(operOid));
936  funcOid = get_opcode(operOid);
937  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
939  get_func_name(funcOid));
940 #endif
941 
942  /* Save the info */
943  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
944  member->is_func = false;
945  member->object = operOid;
946  member->number = item->number;
947  member->sortfamily = sortfamilyOid;
948  /* We can set up dependency fields immediately */
949  /* Historically, ALTER ADD has created soft dependencies */
950  member->ref_is_hard = false;
951  member->ref_is_family = true;
952  member->refobjid = opfamilyoid;
953  assignOperTypes(member, amoid, InvalidOid);
954  addFamilyMember(&operators, member);
955  break;
957  if (item->number <= 0 || item->number > maxProcNumber)
958  ereport(ERROR,
959  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
960  errmsg("invalid function number %d,"
961  " must be between 1 and %d",
962  item->number, maxProcNumber)));
963  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
964 #ifdef NOT_USED
965  /* XXX this is unnecessary given the superuser check above */
966  /* Caller must own function */
967  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
969  get_func_name(funcOid));
970 #endif
971 
972  /* Save the info */
973  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
974  member->is_func = true;
975  member->object = funcOid;
976  member->number = item->number;
977  /* We can set up dependency fields immediately */
978  /* Historically, ALTER ADD has created soft dependencies */
979  member->ref_is_hard = false;
980  member->ref_is_family = true;
981  member->refobjid = opfamilyoid;
982 
983  /* allow overriding of the function's actual arg types */
984  if (item->class_args)
986  &member->lefttype, &member->righttype);
987 
988  assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
989  addFamilyMember(&procedures, member);
990  break;
992  ereport(ERROR,
993  (errcode(ERRCODE_SYNTAX_ERROR),
994  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
995  break;
996  default:
997  elog(ERROR, "unrecognized item type: %d", item->itemtype);
998  break;
999  }
1000  }
1001 
1002  /*
1003  * Let the index AM editorialize on the dependency choices. It could also
1004  * do further validation on the operators and functions, if it likes.
1005  */
1006  if (amroutine->amadjustmembers)
1007  amroutine->amadjustmembers(opfamilyoid,
1008  InvalidOid, /* no specific opclass */
1009  operators,
1010  procedures);
1011 
1012  /*
1013  * Add tuples to pg_amop and pg_amproc tying in the operators and
1014  * functions. Dependencies on them are inserted, too.
1015  */
1016  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
1017  operators, true);
1018  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
1019  procedures, true);
1020 
1021  /* make information available to event triggers */
1022  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1023  operators, procedures);
1024 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4799
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
char * get_opname(Oid opno)
Definition: lsyscache.c:1292
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1267
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1590
void * palloc0(Size size)
Definition: mcxt.c:1230
Oid GetUserId(void)
Definition: miscinit.c:497
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1137
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1536
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1429
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
Definition: opclasscmds.c:1203
static void addFamilyMember(List **list, OpFamilyMember *member)
Definition: opclasscmds.c:1392
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1108
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2208
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:145
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2826
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2824
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2825
@ OBJECT_OPERATOR
Definition: parsenodes.h:1913
@ OBJECT_FUNCTION
Definition: parsenodes.h:1907
#define lfirst_node(type, lc)
Definition: pg_list.h:174
#define NIL
Definition: pg_list.h:66
#define InvalidOid
Definition: postgres_ext.h:36
ObjectWithArgs * name
Definition: parsenodes.h:2832
amadjustmembers_function amadjustmembers
Definition: amapi.h:270
Definition: pg_list.h:52
Oid refobjid
Definition: amapi.h:90
bool ref_is_family
Definition: amapi.h:89
Oid object
Definition: amapi.h:83
bool ref_is_hard
Definition: amapi.h:88
Oid sortfamily
Definition: amapi.h:87

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(), CreateOpClassItem::name, NIL, OpFamilyMember::number, CreateOpClassItem::number, ObjectWithArgs::objargs, OpFamilyMember::object, OBJECT_FUNCTION, OBJECT_OPERATOR, object_ownercheck(), OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, AlterOpFamilyStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), processTypesSpec(), OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, OpFamilyMember::righttype, OpFamilyMember::sortfamily, storeOperators(), and storeProcedures().

Referenced by AlterOpFamily().

◆ AlterOpFamilyDrop()

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

Definition at line 1030 of file opclasscmds.c.

1032 {
1033  List *operators; /* OpFamilyMember list for operators */
1034  List *procedures; /* OpFamilyMember list for support procs */
1035  ListCell *l;
1036 
1037  operators = NIL;
1038  procedures = NIL;
1039 
1040  /*
1041  * Scan the "items" list to obtain additional info.
1042  */
1043  foreach(l, items)
1044  {
1046  Oid lefttype,
1047  righttype;
1048  OpFamilyMember *member;
1049 
1050  switch (item->itemtype)
1051  {
1052  case OPCLASS_ITEM_OPERATOR:
1053  if (item->number <= 0 || item->number > maxOpNumber)
1054  ereport(ERROR,
1055  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1056  errmsg("invalid operator number %d,"
1057  " must be between 1 and %d",
1058  item->number, maxOpNumber)));
1059  processTypesSpec(item->class_args, &lefttype, &righttype);
1060  /* Save the info */
1061  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1062  member->is_func = false;
1063  member->number = item->number;
1064  member->lefttype = lefttype;
1065  member->righttype = righttype;
1066  addFamilyMember(&operators, member);
1067  break;
1068  case OPCLASS_ITEM_FUNCTION:
1069  if (item->number <= 0 || item->number > maxProcNumber)
1070  ereport(ERROR,
1071  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1072  errmsg("invalid function number %d,"
1073  " must be between 1 and %d",
1074  item->number, maxProcNumber)));
1075  processTypesSpec(item->class_args, &lefttype, &righttype);
1076  /* Save the info */
1077  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1078  member->is_func = true;
1079  member->number = item->number;
1080  member->lefttype = lefttype;
1081  member->righttype = righttype;
1082  addFamilyMember(&procedures, member);
1083  break;
1085  /* grammar prevents this from appearing */
1086  default:
1087  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1088  break;
1089  }
1090  }
1091 
1092  /*
1093  * Remove tuples from pg_amop and pg_amproc.
1094  */
1095  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1096  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1097 
1098  /* make information available to event triggers */
1099  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1100  operators, procedures);
1101 }
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1628
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1668

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

Referenced by AlterOpFamily().

◆ assignOperTypes()

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

Definition at line 1137 of file opclasscmds.c.

1138 {
1139  Operator optup;
1140  Form_pg_operator opform;
1141 
1142  /* Fetch the operator definition */
1143  optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1144  if (!HeapTupleIsValid(optup))
1145  elog(ERROR, "cache lookup failed for operator %u", member->object);
1146  opform = (Form_pg_operator) GETSTRUCT(optup);
1147 
1148  /*
1149  * Opfamily operators must be binary.
1150  */
1151  if (opform->oprkind != 'b')
1152  ereport(ERROR,
1153  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1154  errmsg("index operators must be binary")));
1155 
1156  if (OidIsValid(member->sortfamily))
1157  {
1158  /*
1159  * Ordering op, check index supports that. (We could perhaps also
1160  * check that the operator returns a type supported by the sortfamily,
1161  * but that seems more trouble than it's worth here. If it does not,
1162  * the operator will never be matchable to any ORDER BY clause, but no
1163  * worse consequences can ensue. Also, trying to check that would
1164  * create an ordering hazard during dump/reload: it's possible that
1165  * the family has been created but not yet populated with the required
1166  * operators.)
1167  */
1168  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
1169 
1170  if (!amroutine->amcanorderbyop)
1171  ereport(ERROR,
1172  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1173  errmsg("access method \"%s\" does not support ordering operators",
1174  get_am_name(amoid))));
1175  }
1176  else
1177  {
1178  /*
1179  * Search operators must return boolean.
1180  */
1181  if (opform->oprresult != BOOLOID)
1182  ereport(ERROR,
1183  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1184  errmsg("index search operators must return boolean")));
1185  }
1186 
1187  /*
1188  * If lefttype/righttype isn't specified, use the operator's input types
1189  */
1190  if (!OidIsValid(member->lefttype))
1191  member->lefttype = opform->oprleft;
1192  if (!OidIsValid(member->righttype))
1193  member->righttype = opform->oprright;
1194 
1195  ReleaseSysCache(optup);
1196 }
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
#define OidIsValid(objectId)
Definition: c.h:711
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
bool amcanorderbyop
Definition: amapi.h:222
@ OPEROID
Definition: syscache.h:72

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().

◆ assignProcTypes()

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

Definition at line 1203 of file opclasscmds.c.

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

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().

◆ CreateOpFamily()

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

Definition at line 243 of file opclasscmds.c.

245 {
246  Oid opfamilyoid;
247  Relation rel;
248  HeapTuple tup;
249  Datum values[Natts_pg_opfamily];
250  bool nulls[Natts_pg_opfamily];
251  NameData opfName;
252  ObjectAddress myself,
253  referenced;
254 
255  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
256 
257  /*
258  * Make sure there is no existing opfamily of this name (this is just to
259  * give a more friendly error message than "duplicate key").
260  */
262  ObjectIdGetDatum(amoid),
263  CStringGetDatum(opfname),
264  ObjectIdGetDatum(namespaceoid)))
265  ereport(ERROR,
267  errmsg("operator family \"%s\" for access method \"%s\" already exists",
268  opfname, stmt->amname)));
269 
270  /*
271  * Okay, let's create the pg_opfamily entry.
272  */
273  memset(values, 0, sizeof(values));
274  memset(nulls, false, sizeof(nulls));
275 
276  opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
277  Anum_pg_opfamily_oid);
278  values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
279  values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
280  namestrcpy(&opfName, opfname);
281  values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
282  values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
283  values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
284 
285  tup = heap_form_tuple(rel->rd_att, values, nulls);
286 
287  CatalogTupleInsert(rel, tup);
288 
289  heap_freetuple(tup);
290 
291  /*
292  * Create dependencies for the opfamily proper.
293  */
294  myself.classId = OperatorFamilyRelationId;
295  myself.objectId = opfamilyoid;
296  myself.objectSubId = 0;
297 
298  /* dependency on access method */
299  referenced.classId = AccessMethodRelationId;
300  referenced.objectId = amoid;
301  referenced.objectSubId = 0;
302  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
303 
304  /* dependency on namespace */
305  referenced.classId = NamespaceRelationId;
306  referenced.objectId = namespaceoid;
307  referenced.objectSubId = 0;
308  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
309 
310  /* dependency on owner */
311  recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
312 
313  /* dependency on extension */
314  recordDependencyOnCurrentExtension(&myself, false);
315 
316  /* Report the new operator family to possibly interested event triggers */
318  (Node *) stmt);
319 
320  /* Post creation hook for new operator family */
321  InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
322 
324 
325  return myself;
326 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
@ DEPENDENCY_AUTO
Definition: dependency.h:34
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
void EventTriggerCollectSimpleCommand(ObjectAddress address, ObjectAddress secondaryObject, Node *parsetree)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define RowExclusiveLock
Definition: lockdefs.h:38
void namestrcpy(Name name, const char *str)
Definition: name.c:233
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
const ObjectAddress InvalidObjectAddress
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
uintptr_t Datum
Definition: postgres.h:412
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:721
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
Definition: nodes.h:118
TupleDesc rd_att
Definition: rel.h:111
Definition: c.h:677
@ OPFAMILYAMNAMENSP
Definition: syscache.h:73
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:192
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

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

Referenced by DefineOpClass(), and DefineOpFamily().

◆ DefineOpClass()

ObjectAddress DefineOpClass ( CreateOpClassStmt stmt)

Definition at line 333 of file opclasscmds.c.

334 {
335  char *opcname; /* name of opclass we're creating */
336  Oid amoid, /* our AM's oid */
337  typeoid, /* indexable datatype oid */
338  storageoid, /* storage datatype oid, if any */
339  namespaceoid, /* namespace to create opclass in */
340  opfamilyoid, /* oid of containing opfamily */
341  opclassoid; /* oid of opclass we create */
342  int maxOpNumber, /* amstrategies value */
343  optsProcNumber, /* amoptsprocnum value */
344  maxProcNumber; /* amsupport value */
345  bool amstorage; /* amstorage flag */
346  List *operators; /* OpFamilyMember list for operators */
347  List *procedures; /* OpFamilyMember list for support procs */
348  ListCell *l;
349  Relation rel;
350  HeapTuple tup;
351  Form_pg_am amform;
352  IndexAmRoutine *amroutine;
353  Datum values[Natts_pg_opclass];
354  bool nulls[Natts_pg_opclass];
355  AclResult aclresult;
356  NameData opcName;
357  ObjectAddress myself,
358  referenced;
359 
360  /* Convert list of names to a name and namespace */
361  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
362  &opcname);
363 
364  /* Check we have creation rights in target namespace */
365  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
366  if (aclresult != ACLCHECK_OK)
367  aclcheck_error(aclresult, OBJECT_SCHEMA,
368  get_namespace_name(namespaceoid));
369 
370  /* Get necessary info about access method */
372  if (!HeapTupleIsValid(tup))
373  ereport(ERROR,
374  (errcode(ERRCODE_UNDEFINED_OBJECT),
375  errmsg("access method \"%s\" does not exist",
376  stmt->amname)));
377 
378  amform = (Form_pg_am) GETSTRUCT(tup);
379  amoid = amform->oid;
380  amroutine = GetIndexAmRoutineByAmId(amoid, false);
381  ReleaseSysCache(tup);
382 
383  maxOpNumber = amroutine->amstrategies;
384  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
385  if (maxOpNumber <= 0)
386  maxOpNumber = SHRT_MAX;
387  maxProcNumber = amroutine->amsupport;
388  optsProcNumber = amroutine->amoptsprocnum;
389  amstorage = amroutine->amstorage;
390 
391  /* XXX Should we make any privilege check against the AM? */
392 
393  /*
394  * The question of appropriate permissions for CREATE OPERATOR CLASS is
395  * interesting. Creating an opclass is tantamount to granting public
396  * execute access on the functions involved, since the index machinery
397  * generally does not check access permission before using the functions.
398  * A minimum expectation therefore is that the caller have execute
399  * privilege with grant option. Since we don't have a way to make the
400  * opclass go away if the grant option is revoked, we choose instead to
401  * require ownership of the functions. It's also not entirely clear what
402  * permissions should be required on the datatype, but ownership seems
403  * like a safe choice.
404  *
405  * Currently, we require superuser privileges to create an opclass. This
406  * seems necessary because we have no way to validate that the offered set
407  * of operators and functions are consistent with the AM's expectations.
408  * It would be nice to provide such a check someday, if it can be done
409  * without solving the halting problem :-(
410  *
411  * XXX re-enable NOT_USED code sections below if you remove this test.
412  */
413  if (!superuser())
414  ereport(ERROR,
415  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
416  errmsg("must be superuser to create an operator class")));
417 
418  /* Look up the datatype */
419  typeoid = typenameTypeId(NULL, stmt->datatype);
420 
421 #ifdef NOT_USED
422  /* XXX this is unnecessary given the superuser check above */
423  /* Check we have ownership of the datatype */
424  if (!object_ownercheck(TypeRelationId, typeoid, GetUserId()))
426 #endif
427 
428  /*
429  * Look up the containing operator family, or create one if FAMILY option
430  * was omitted and there's not a match already.
431  */
432  if (stmt->opfamilyname)
433  {
434  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
435  }
436  else
437  {
438  /* Lookup existing family of same name and namespace */
440  ObjectIdGetDatum(amoid),
441  PointerGetDatum(opcname),
442  ObjectIdGetDatum(namespaceoid));
443  if (HeapTupleIsValid(tup))
444  {
445  opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
446 
447  /*
448  * XXX given the superuser check above, there's no need for an
449  * ownership check here
450  */
451  ReleaseSysCache(tup);
452  }
453  else
454  {
455  CreateOpFamilyStmt *opfstmt;
456  ObjectAddress tmpAddr;
457 
458  opfstmt = makeNode(CreateOpFamilyStmt);
459  opfstmt->opfamilyname = stmt->opclassname;
460  opfstmt->amname = stmt->amname;
461 
462  /*
463  * Create it ... again no need for more permissions ...
464  */
465  tmpAddr = CreateOpFamily(opfstmt, opcname, namespaceoid, amoid);
466  opfamilyoid = tmpAddr.objectId;
467  }
468  }
469 
470  operators = NIL;
471  procedures = NIL;
472 
473  /* Storage datatype is optional */
474  storageoid = InvalidOid;
475 
476  /*
477  * Scan the "items" list to obtain additional info.
478  */
479  foreach(l, stmt->items)
480  {
482  Oid operOid;
483  Oid funcOid;
484  Oid sortfamilyOid;
485  OpFamilyMember *member;
486 
487  switch (item->itemtype)
488  {
490  if (item->number <= 0 || item->number > maxOpNumber)
491  ereport(ERROR,
492  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
493  errmsg("invalid operator number %d,"
494  " must be between 1 and %d",
495  item->number, maxOpNumber)));
496  if (item->name->objargs != NIL)
497  operOid = LookupOperWithArgs(item->name, false);
498  else
499  {
500  /* Default to binary op on input datatype */
501  operOid = LookupOperName(NULL, item->name->objname,
502  typeoid, typeoid,
503  false, -1);
504  }
505 
506  if (item->order_family)
507  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
508  item->order_family,
509  false);
510  else
511  sortfamilyOid = InvalidOid;
512 
513 #ifdef NOT_USED
514  /* XXX this is unnecessary given the superuser check above */
515  /* Caller must own operator and its underlying function */
516  if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
518  get_opname(operOid));
519  funcOid = get_opcode(operOid);
520  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
522  get_func_name(funcOid));
523 #endif
524 
525  /* Save the info */
526  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
527  member->is_func = false;
528  member->object = operOid;
529  member->number = item->number;
530  member->sortfamily = sortfamilyOid;
531  assignOperTypes(member, amoid, typeoid);
532  addFamilyMember(&operators, member);
533  break;
535  if (item->number <= 0 || item->number > maxProcNumber)
536  ereport(ERROR,
537  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
538  errmsg("invalid function number %d,"
539  " must be between 1 and %d",
540  item->number, maxProcNumber)));
541  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
542 #ifdef NOT_USED
543  /* XXX this is unnecessary given the superuser check above */
544  /* Caller must own function */
545  if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
547  get_func_name(funcOid));
548 #endif
549  /* Save the info */
550  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
551  member->is_func = true;
552  member->object = funcOid;
553  member->number = item->number;
554 
555  /* allow overriding of the function's actual arg types */
556  if (item->class_args)
558  &member->lefttype, &member->righttype);
559 
560  assignProcTypes(member, amoid, typeoid, optsProcNumber);
561  addFamilyMember(&procedures, member);
562  break;
564  if (OidIsValid(storageoid))
565  ereport(ERROR,
566  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
567  errmsg("storage type specified more than once")));
568  storageoid = typenameTypeId(NULL, item->storedtype);
569 
570 #ifdef NOT_USED
571  /* XXX this is unnecessary given the superuser check above */
572  /* Check we have ownership of the datatype */
573  if (!object_ownercheck(TypeRelationId, storageoid, GetUserId()))
575 #endif
576  break;
577  default:
578  elog(ERROR, "unrecognized item type: %d", item->itemtype);
579  break;
580  }
581  }
582 
583  /*
584  * If storagetype is specified, make sure it's legal.
585  */
586  if (OidIsValid(storageoid))
587  {
588  /* Just drop the spec if same as column datatype */
589  if (storageoid == typeoid)
590  storageoid = InvalidOid;
591  else if (!amstorage)
592  ereport(ERROR,
593  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
594  errmsg("storage type cannot be different from data type for access method \"%s\"",
595  stmt->amname)));
596  }
597 
598  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
599 
600  /*
601  * Make sure there is no existing opclass of this name (this is just to
602  * give a more friendly error message than "duplicate key").
603  */
605  ObjectIdGetDatum(amoid),
606  CStringGetDatum(opcname),
607  ObjectIdGetDatum(namespaceoid)))
608  ereport(ERROR,
610  errmsg("operator class \"%s\" for access method \"%s\" already exists",
611  opcname, stmt->amname)));
612 
613  /*
614  * If we are creating a default opclass, check there isn't one already.
615  * (Note we do not restrict this test to visible opclasses; this ensures
616  * that typcache.c can find unique solutions to its questions.)
617  */
618  if (stmt->isDefault)
619  {
620  ScanKeyData skey[1];
621  SysScanDesc scan;
622 
623  ScanKeyInit(&skey[0],
624  Anum_pg_opclass_opcmethod,
625  BTEqualStrategyNumber, F_OIDEQ,
626  ObjectIdGetDatum(amoid));
627 
628  scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
629  NULL, 1, skey);
630 
631  while (HeapTupleIsValid(tup = systable_getnext(scan)))
632  {
633  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
634 
635  if (opclass->opcintype == typeoid && opclass->opcdefault)
636  ereport(ERROR,
638  errmsg("could not make operator class \"%s\" be default for type %s",
639  opcname,
640  TypeNameToString(stmt->datatype)),
641  errdetail("Operator class \"%s\" already is the default.",
642  NameStr(opclass->opcname))));
643  }
644 
645  systable_endscan(scan);
646  }
647 
648  /*
649  * Okay, let's create the pg_opclass entry.
650  */
651  memset(values, 0, sizeof(values));
652  memset(nulls, false, sizeof(nulls));
653 
654  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
655  Anum_pg_opclass_oid);
656  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
657  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
658  namestrcpy(&opcName, opcname);
659  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
660  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
661  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
662  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
663  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
664  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
665  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
666 
667  tup = heap_form_tuple(rel->rd_att, values, nulls);
668 
669  CatalogTupleInsert(rel, tup);
670 
671  heap_freetuple(tup);
672 
673  /*
674  * Now that we have the opclass OID, set up default dependency info for
675  * the pg_amop and pg_amproc entries. Historically, CREATE OPERATOR CLASS
676  * has created hard dependencies on the opclass, so that's what we use.
677  */
678  foreach(l, operators)
679  {
680  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
681 
682  op->ref_is_hard = true;
683  op->ref_is_family = false;
684  op->refobjid = opclassoid;
685  }
686  foreach(l, procedures)
687  {
688  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
689 
690  proc->ref_is_hard = true;
691  proc->ref_is_family = false;
692  proc->refobjid = opclassoid;
693  }
694 
695  /*
696  * Let the index AM editorialize on the dependency choices. It could also
697  * do further validation on the operators and functions, if it likes.
698  */
699  if (amroutine->amadjustmembers)
700  amroutine->amadjustmembers(opfamilyoid,
701  opclassoid,
702  operators,
703  procedures);
704 
705  /*
706  * Now add tuples to pg_amop and pg_amproc tying in the operators and
707  * functions. Dependencies on them are inserted, too.
708  */
709  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
710  operators, false);
711  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
712  procedures, false);
713 
714  /* let event triggers know what happened */
715  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
716 
717  /*
718  * Create dependencies for the opclass proper. Note: we do not need a
719  * dependency link to the AM, because that exists through the opfamily.
720  */
721  myself.classId = OperatorClassRelationId;
722  myself.objectId = opclassoid;
723  myself.objectSubId = 0;
724 
725  /* dependency on namespace */
726  referenced.classId = NamespaceRelationId;
727  referenced.objectId = namespaceoid;
728  referenced.objectSubId = 0;
729  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
730 
731  /* dependency on opfamily */
732  referenced.classId = OperatorFamilyRelationId;
733  referenced.objectId = opfamilyoid;
734  referenced.objectSubId = 0;
735  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
736 
737  /* dependency on indexed datatype */
738  referenced.classId = TypeRelationId;
739  referenced.objectId = typeoid;
740  referenced.objectSubId = 0;
741  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
742 
743  /* dependency on storage datatype */
744  if (OidIsValid(storageoid))
745  {
746  referenced.classId = TypeRelationId;
747  referenced.objectId = storageoid;
748  referenced.objectSubId = 0;
749  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
750  }
751 
752  /* dependency on owner */
753  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
754 
755  /* dependency on extension */
756  recordDependencyOnCurrentExtension(&myself, false);
757 
758  /* Post creation hook for new operator class */
759  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
760 
762 
763  return myself;
764 }
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3804
#define NameStr(name)
Definition: c.h:682
int errdetail(const char *fmt,...)
Definition: elog.c:1202
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:599
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:506
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:387
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3331
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:3038
#define makeNode(_type_)
Definition: nodes.h:165
static ObjectAddress CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:243
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:101
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:478
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
@ OBJECT_SCHEMA
Definition: parsenodes.h:1924
#define ACL_CREATE
Definition: parsenodes.h:92
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define BTEqualStrategyNumber
Definition: stratnum.h:31
TypeName * storedtype
Definition: parsenodes.h:2838
TypeName * datatype
Definition: parsenodes.h:2819
bool amstorage
Definition: amapi.h:236
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1195
@ CLAAMNAMENSP
Definition: syscache.h:47

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), IndexAmRoutine::amadjustmembers, CreateOpClassStmt::amname, CreateOpFamilyStmt::amname, AMNAME, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, assignOperTypes(), assignProcTypes(), BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleInsert(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum(), CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, EventTriggerCollectCreateOpClass(), get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GetIndexAmRoutineByAmId(), GetNewOidWithIndex(), GETSTRUCT, GetUserId(), heap_form_tuple(), heap_freetuple(), HeapTupleIsValid, InvalidOid, InvokeObjectPostCreateHook, OpFamilyMember::is_func, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, lfirst_node, LookupFuncWithArgs(), LookupOperName(), LookupOperWithArgs(), makeNode, CreateOpClassItem::name, NameGetDatum(), NameStr, namestrcpy(), NIL, OpFamilyMember::number, CreateOpClassItem::number, ObjectWithArgs::objargs, OpFamilyMember::object, object_aclcheck(), OBJECT_FUNCTION, OBJECT_OPERATOR, object_ownercheck(), OBJECT_SCHEMA, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, ObjectWithArgs::objname, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, CreateOpClassStmt::opclassname, OPFAMILYAMNAMENSP, CreateOpClassStmt::opfamilyname, CreateOpFamilyStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), 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().

◆ DefineOpFamily()

ObjectAddress DefineOpFamily ( CreateOpFamilyStmt stmt)

Definition at line 772 of file opclasscmds.c.

773 {
774  char *opfname; /* name of opfamily we're creating */
775  Oid amoid, /* our AM's oid */
776  namespaceoid; /* namespace to create opfamily in */
777  AclResult aclresult;
778 
779  /* Convert list of names to a name and namespace */
780  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
781  &opfname);
782 
783  /* Check we have creation rights in target namespace */
784  aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE);
785  if (aclresult != ACLCHECK_OK)
786  aclcheck_error(aclresult, OBJECT_SCHEMA,
787  get_namespace_name(namespaceoid));
788 
789  /* Get access method OID, throwing an error if it doesn't exist. */
790  amoid = get_index_am_oid(stmt->amname, false);
791 
792  /* XXX Should we make any privilege check against the AM? */
793 
794  /*
795  * Currently, we require superuser privileges to create an opfamily. See
796  * comments in DefineOpClass.
797  */
798  if (!superuser())
799  ereport(ERROR,
800  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
801  errmsg("must be superuser to create an operator family")));
802 
803  /* Insert pg_opfamily catalog entry */
804  return CreateOpFamily(stmt, opfname, namespaceoid, amoid);
805 }
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:163

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

Referenced by ProcessUtilitySlow().

◆ dropOperators()

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

Definition at line 1628 of file opclasscmds.c.

1630 {
1631  ListCell *l;
1632 
1633  foreach(l, operators)
1634  {
1635  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1636  Oid amopid;
1637  ObjectAddress object;
1638 
1639  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1640  ObjectIdGetDatum(opfamilyoid),
1643  Int16GetDatum(op->number));
1644  if (!OidIsValid(amopid))
1645  ereport(ERROR,
1646  (errcode(ERRCODE_UNDEFINED_OBJECT),
1647  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1648  op->number,
1649  format_type_be(op->lefttype),
1651  NameListToString(opfamilyname))));
1652 
1653  object.classId = AccessMethodOperatorRelationId;
1654  object.objectId = amopid;
1655  object.objectSubId = 0;
1656 
1657  performDeletion(&object, DROP_RESTRICT, 0);
1658  }
1659 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:322
char * NameListToString(List *names)
Definition: namespace.c:3145
@ DROP_RESTRICT
Definition: parsenodes.h:1961
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:520
@ AMOPSTRATEGY
Definition: syscache.h:38
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:203

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().

◆ dropProcedures()

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

Definition at line 1668 of file opclasscmds.c.

1670 {
1671  ListCell *l;
1672 
1673  foreach(l, procedures)
1674  {
1675  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1676  Oid amprocid;
1677  ObjectAddress object;
1678 
1679  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1680  ObjectIdGetDatum(opfamilyoid),
1683  Int16GetDatum(op->number));
1684  if (!OidIsValid(amprocid))
1685  ereport(ERROR,
1686  (errcode(ERRCODE_UNDEFINED_OBJECT),
1687  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1688  op->number,
1689  format_type_be(op->lefttype),
1691  NameListToString(opfamilyname))));
1692 
1693  object.classId = AccessMethodProcedureRelationId;
1694  object.objectId = amprocid;
1695  object.objectSubId = 0;
1696 
1697  performDeletion(&object, DROP_RESTRICT, 0);
1698  }
1699 }
@ AMPROCNUM
Definition: syscache.h:39

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().

◆ get_opclass_oid()

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

Definition at line 220 of file opclasscmds.c.

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 }
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:162

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

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

◆ get_opfamily_oid()

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

Definition at line 139 of file opclasscmds.c.

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 }
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:81

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

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

◆ IsThereOpClassInNamespace()

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

Definition at line 1708 of file opclasscmds.c.

1710 {
1711  /* make sure the new name doesn't exist */
1713  ObjectIdGetDatum(opcmethod),
1714  CStringGetDatum(opcname),
1715  ObjectIdGetDatum(opcnamespace)))
1716  ereport(ERROR,
1718  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1719  opcname,
1720  get_am_name(opcmethod),
1721  get_namespace_name(opcnamespace))));
1722 }

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().

◆ IsThereOpFamilyInNamespace()

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

Definition at line 1731 of file opclasscmds.c.

1733 {
1734  /* make sure the new name doesn't exist */
1736  ObjectIdGetDatum(opfmethod),
1737  CStringGetDatum(opfname),
1738  ObjectIdGetDatum(opfnamespace)))
1739  ereport(ERROR,
1741  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1742  opfname,
1743  get_am_name(opfmethod),
1744  get_namespace_name(opfnamespace))));
1745 }

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().

◆ OpClassCacheLookup()

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

Definition at line 162 of file opclasscmds.c.

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 OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1843
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2936
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2852
@ AMOID
Definition: syscache.h:36
@ CLAOID
Definition: syscache.h:48

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().

◆ OpFamilyCacheLookup()

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

Definition at line 81 of file opclasscmds.c.

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 OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1926
@ OPFAMILYOID
Definition: syscache.h:74

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().

◆ processTypesSpec()

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

Definition at line 1108 of file opclasscmds.c.

1109 {
1110  TypeName *typeName;
1111 
1112  Assert(args != NIL);
1113 
1114  typeName = (TypeName *) linitial(args);
1115  *lefttype = typenameTypeId(NULL, typeName);
1116 
1117  if (list_length(args) > 1)
1118  {
1119  typeName = (TypeName *) lsecond(args);
1120  *righttype = typenameTypeId(NULL, typeName);
1121  }
1122  else
1123  *righttype = *lefttype;
1124 
1125  if (list_length(args) > 2)
1126  ereport(ERROR,
1127  (errcode(ERRCODE_SYNTAX_ERROR),
1128  errmsg("one or two argument types must be specified")));
1129 }
Assert(fmt[strlen(fmt) - 1] !='\n')
static int list_length(const List *l)
Definition: pg_list.h:150
#define linitial(l)
Definition: pg_list.h:176
#define lsecond(l)
Definition: pg_list.h:181

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

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

◆ storeOperators()

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

Definition at line 1429 of file opclasscmds.c.

1431 {
1432  Relation rel;
1433  Datum values[Natts_pg_amop];
1434  bool nulls[Natts_pg_amop];
1435  HeapTuple tup;
1436  Oid entryoid;
1437  ObjectAddress myself,
1438  referenced;
1439  ListCell *l;
1440 
1441  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1442 
1443  foreach(l, operators)
1444  {
1445  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1446  char oppurpose;
1447 
1448  /*
1449  * If adding to an existing family, check for conflict with an
1450  * existing pg_amop entry (just to give a nicer error message)
1451  */
1452  if (isAdd &&
1454  ObjectIdGetDatum(opfamilyoid),
1457  Int16GetDatum(op->number)))
1458  ereport(ERROR,
1460  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1461  op->number,
1462  format_type_be(op->lefttype),
1464  NameListToString(opfamilyname))));
1465 
1466  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1467 
1468  /* Create the pg_amop entry */
1469  memset(values, 0, sizeof(values));
1470  memset(nulls, false, sizeof(nulls));
1471 
1472  entryoid = GetNewOidWithIndex(rel, AccessMethodOperatorOidIndexId,
1473  Anum_pg_amop_oid);
1474  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1475  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1476  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1477  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1478  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1479  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1480  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1481  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1482  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1483 
1484  tup = heap_form_tuple(rel->rd_att, values, nulls);
1485 
1486  CatalogTupleInsert(rel, tup);
1487 
1488  heap_freetuple(tup);
1489 
1490  /* Make its dependencies */
1491  myself.classId = AccessMethodOperatorRelationId;
1492  myself.objectId = entryoid;
1493  myself.objectSubId = 0;
1494 
1495  referenced.classId = OperatorRelationId;
1496  referenced.objectId = op->object;
1497  referenced.objectSubId = 0;
1498 
1499  /* see comments in amapi.h about dependency strength */
1500  recordDependencyOn(&myself, &referenced,
1502 
1503  referenced.classId = op->ref_is_family ? OperatorFamilyRelationId :
1504  OperatorClassRelationId;
1505  referenced.objectId = op->refobjid;
1506  referenced.objectSubId = 0;
1507 
1508  recordDependencyOn(&myself, &referenced,
1510 
1511  /* A search operator also needs a dep on the referenced opfamily */
1512  if (OidIsValid(op->sortfamily))
1513  {
1514  referenced.classId = OperatorFamilyRelationId;
1515  referenced.objectId = op->sortfamily;
1516  referenced.objectSubId = 0;
1517 
1518  recordDependencyOn(&myself, &referenced,
1520  }
1521 
1522  /* Post create hook of this access method operator */
1523  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1524  entryoid, 0);
1525  }
1526 
1528 }
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
static Datum CharGetDatum(char X)
Definition: postgres.h:470
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:194

References 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().

◆ storeProcedures()

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

Definition at line 1536 of file opclasscmds.c.

1538 {
1539  Relation rel;
1540  Datum values[Natts_pg_amproc];
1541  bool nulls[Natts_pg_amproc];
1542  HeapTuple tup;
1543  Oid entryoid;
1544  ObjectAddress myself,
1545  referenced;
1546  ListCell *l;
1547 
1548  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1549 
1550  foreach(l, procedures)
1551  {
1552  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1553 
1554  /*
1555  * If adding to an existing family, check for conflict with an
1556  * existing pg_amproc entry (just to give a nicer error message)
1557  */
1558  if (isAdd &&
1560  ObjectIdGetDatum(opfamilyoid),
1561  ObjectIdGetDatum(proc->lefttype),
1562  ObjectIdGetDatum(proc->righttype),
1563  Int16GetDatum(proc->number)))
1564  ereport(ERROR,
1566  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1567  proc->number,
1568  format_type_be(proc->lefttype),
1569  format_type_be(proc->righttype),
1570  NameListToString(opfamilyname))));
1571 
1572  /* Create the pg_amproc entry */
1573  memset(values, 0, sizeof(values));
1574  memset(nulls, false, sizeof(nulls));
1575 
1576  entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId,
1577  Anum_pg_amproc_oid);
1578  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1579  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1580  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1581  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1582  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1583  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1584 
1585  tup = heap_form_tuple(rel->rd_att, values, nulls);
1586 
1587  CatalogTupleInsert(rel, tup);
1588 
1589  heap_freetuple(tup);
1590 
1591  /* Make its dependencies */
1592  myself.classId = AccessMethodProcedureRelationId;
1593  myself.objectId = entryoid;
1594  myself.objectSubId = 0;
1595 
1596  referenced.classId = ProcedureRelationId;
1597  referenced.objectId = proc->object;
1598  referenced.objectSubId = 0;
1599 
1600  /* see comments in amapi.h about dependency strength */
1601  recordDependencyOn(&myself, &referenced,
1603 
1604  referenced.classId = proc->ref_is_family ? OperatorFamilyRelationId :
1605  OperatorClassRelationId;
1606  referenced.objectId = proc->refobjid;
1607  referenced.objectSubId = 0;
1608 
1609  recordDependencyOn(&myself, &referenced,
1611 
1612  /* Post create hook of access method procedure */
1613  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1614  entryoid, 0);
1615  }
1616 
1618 }

References 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().