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/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/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/acl.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 bool typeDepNeeded (Oid typid, OpFamilyMember *member)
 
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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
List * lappend(List *list, void *datum)
Definition: list.c:339
#define lfirst(lc)
Definition: pg_list.h:172
Oid lefttype
Definition: amapi.h:91
Oid righttype
Definition: amapi.h:92
int number
Definition: amapi.h:90
bool is_func
Definition: amapi.h:88

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, /* amoptsprocnum value */
823 maxProcNumber; /* amsupport value */
824 HeapTuple tup;
825 Form_pg_am amform;
826 IndexAmRoutine *amroutine;
827
828 /* Get necessary info about access method */
829 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
830 if (!HeapTupleIsValid(tup))
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())
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
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define stmt
Definition: indent_codes.h:59
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:355
unsigned int Oid
Definition: postgres_ext.h:32
uint16 amoptsprocnum
Definition: amapi.h:241
uint16 amsupport
Definition: amapi.h:239
uint16 amstrategies
Definition: amapi.h:237
bool superuser(void)
Definition: superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GetIndexAmRoutineByAmId(), GETSTRUCT(), HeapTupleIsValid, ReleaseSysCache(), SearchSysCache1(), stmt, 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)
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 {
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)
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;
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 */
1023 operators, procedures);
1024}
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4058
#define elog(elevel,...)
Definition: elog.h:225
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
char * get_opname(Oid opno)
Definition: lsyscache.c:1393
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1368
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1691
void * palloc0(Size size)
Definition: mcxt.c:1347
Oid GetUserId(void)
Definition: miscinit.c:520
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:1559
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:2206
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:133
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:3269
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:3267
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:3268
@ OBJECT_OPERATOR
Definition: parsenodes.h:2337
@ OBJECT_FUNCTION
Definition: parsenodes.h:2331
#define lfirst_node(type, lc)
Definition: pg_list.h:176
#define NIL
Definition: pg_list.h:68
#define InvalidOid
Definition: postgres_ext.h:37
ObjectWithArgs * name
Definition: parsenodes.h:3275
amadjustmembers_function amadjustmembers
Definition: amapi.h:305
Definition: pg_list.h:54
Oid refobjid
Definition: amapi.h:96
bool ref_is_family
Definition: amapi.h:95
Oid object
Definition: amapi.h:89
bool ref_is_hard
Definition: amapi.h:94
Oid sortfamily
Definition: amapi.h:93
static ItemArray items
Definition: test_tidstore.c:48

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, items, 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, CreateOpClassItem::order_family, palloc0(), processTypesSpec(), OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, OpFamilyMember::refobjid, OpFamilyMember::righttype, OpFamilyMember::sortfamily, stmt, 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 {
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;
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 */
1100 operators, procedures);
1101}
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1725
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1765

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

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:746
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
bool amcanorderbyop
Definition: amapi.h:245

References IndexAmRoutine::amcanorderbyop, elog, ereport, errcode(), errmsg(), ERROR, get_am_name(), GetIndexAmRoutineByAmId(), GETSTRUCT(), HeapTupleIsValid, OpFamilyMember::lefttype, OpFamilyMember::object, ObjectIdGetDatum(), OidIsValid, 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 * Ordering comparison procs must be 2-arg procs returning int4. Ordering
1246 * sortsupport procs must take internal and return void. Ordering
1247 * in_range procs must be 5-arg procs returning bool. Ordering equalimage
1248 * procs must take 1 arg and return bool. Hashing support proc 1 must be
1249 * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
1250 * returning int8. Otherwise we don't know.
1251 */
1252 else if (GetIndexAmRoutineByAmId(amoid, false)->amcanorder)
1253 {
1254 if (member->number == BTORDER_PROC)
1255 {
1256 if (procform->pronargs != 2)
1257 ereport(ERROR,
1258 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1259 errmsg("ordering comparison functions must have two arguments")));
1260 if (procform->prorettype != INT4OID)
1261 ereport(ERROR,
1262 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1263 errmsg("ordering 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("ordering sort support functions must accept type \"internal\"")));
1281 if (procform->prorettype != VOIDOID)
1282 ereport(ERROR,
1283 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1284 errmsg("ordering 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("ordering in_range functions must have five arguments")));
1296 if (procform->prorettype != BOOLOID)
1297 ereport(ERROR,
1298 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1299 errmsg("ordering 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("ordering equal image functions must have one argument")));
1316 if (procform->prorettype != BOOLOID)
1317 ereport(ERROR,
1318 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1319 errmsg("ordering 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 lefttype 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("ordering equal image functions must not be cross-type")));
1333 }
1334 }
1335 else if (GetIndexAmRoutineByAmId(amoid, false)->amcanhash)
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:1317
#define HASHSTANDARD_PROC
Definition: hash.h:355
#define HASHEXTENDED_PROC
Definition: hash.h:356
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:715
#define BTORDER_PROC
Definition: nbtree.h:712
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:713
#define BTINRANGE_PROC
Definition: nbtree.h:714
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:136

References BTEQUALIMAGE_PROC, BTINRANGE_PROC, BTORDER_PROC, BTSORTSUPPORT_PROC, elog, ereport, errcode(), errhint(), errmsg(), ERROR, GetIndexAmRoutineByAmId(), GETSTRUCT(), HASHEXTENDED_PROC, HASHSTANDARD_PROC, HeapTupleIsValid, OpFamilyMember::lefttype, OpFamilyMember::number, OpFamilyMember::object, ObjectIdGetDatum(), OidIsValid, 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 */
261 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
262 ObjectIdGetDatum(amoid),
263 CStringGetDatum(opfname),
264 ObjectIdGetDatum(namespaceoid)))
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 */
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:151
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
@ 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, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
#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:45
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
uintptr_t Datum
Definition: postgres.h:69
static Datum NameGetDatum(const NameData *X)
Definition: postgres.h:378
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
Definition: nodes.h:131
TupleDesc rd_att
Definition: rel.h:112
Definition: c.h:712
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:104
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References 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, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, SearchSysCacheExists3, stmt, 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 */
371 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
372 if (!HeapTupleIsValid(tup))
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())
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 */
439 tup = SearchSysCache3(OPFAMILYAMNAMENSP,
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)
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)
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))
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)
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 */
604 if (SearchSysCacheExists3(CLAAMNAMENSP,
605 ObjectIdGetDatum(amoid),
606 CStringGetDatum(opcname),
607 ObjectIdGetDatum(namespaceoid)))
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 {
634
635 if (opclass->opcintype == typeoid && opclass->opcdefault)
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 {
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 */
757
758 /* Post creation hook for new operator class */
759 InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
760
762
763 return myself;
764}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:2941
#define NameStr(name)
Definition: c.h:717
int errdetail(const char *fmt,...)
Definition: elog.c:1203
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3449
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3487
#define makeNode(_type_)
Definition: nodes.h:157
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:99
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:2348
#define ACL_CREATE
Definition: parsenodes.h:85
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:327
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
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:3281
bool amstorage
Definition: amapi.h:265
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:243

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), IndexAmRoutine::amadjustmembers, CreateOpFamilyStmt::amname, IndexAmRoutine::amoptsprocnum, IndexAmRoutine::amstorage, IndexAmRoutine::amstrategies, IndexAmRoutine::amsupport, assignOperTypes(), assignProcTypes(), BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleInsert(), CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum(), 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, 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, 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, stmt, 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())
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, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_index_am_oid(), get_namespace_name(), GetUserId(), object_aclcheck(), OBJECT_SCHEMA, QualifiedNameGetCreationNamespace(), stmt, and superuser().

Referenced by ProcessUtilitySlow().

◆ dropOperators()

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

Definition at line 1725 of file opclasscmds.c.

1727{
1728 ListCell *l;
1729
1730 foreach(l, operators)
1731 {
1733 Oid amopid;
1734 ObjectAddress object;
1735
1736 amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1737 ObjectIdGetDatum(opfamilyoid),
1740 Int16GetDatum(op->number));
1741 if (!OidIsValid(amopid))
1742 ereport(ERROR,
1743 (errcode(ERRCODE_UNDEFINED_OBJECT),
1744 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1745 op->number,
1748 NameListToString(opfamilyname))));
1749
1750 object.classId = AccessMethodOperatorRelationId;
1751 object.objectId = amopid;
1752 object.objectSubId = 0;
1753
1754 performDeletion(&object, DROP_RESTRICT, 0);
1755 }
1756}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
char * NameListToString(const List *names)
Definition: namespace.c:3594
@ DROP_RESTRICT
Definition: parsenodes.h:2385
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:177
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:115

References 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 1765 of file opclasscmds.c.

1767{
1768 ListCell *l;
1769
1770 foreach(l, procedures)
1771 {
1773 Oid amprocid;
1774 ObjectAddress object;
1775
1776 amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1777 ObjectIdGetDatum(opfamilyoid),
1780 Int16GetDatum(op->number));
1781 if (!OidIsValid(amprocid))
1782 ereport(ERROR,
1783 (errcode(ERRCODE_UNDEFINED_OBJECT),
1784 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1785 op->number,
1788 NameListToString(opfamilyname))));
1789
1790 object.classId = AccessMethodProcedureRelationId;
1791 object.objectId = amprocid;
1792 object.objectSubId = 0;
1793
1794 performDeletion(&object, DROP_RESTRICT, 0);
1795 }
1796}

References 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 1805 of file opclasscmds.c.

1807{
1808 /* make sure the new name doesn't exist */
1809 if (SearchSysCacheExists3(CLAAMNAMENSP,
1810 ObjectIdGetDatum(opcmethod),
1811 CStringGetDatum(opcname),
1812 ObjectIdGetDatum(opcnamespace)))
1813 ereport(ERROR,
1815 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1816 opcname,
1817 get_am_name(opcmethod),
1818 get_namespace_name(opcnamespace))));
1819}

References 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 1828 of file opclasscmds.c.

1830{
1831 /* make sure the new name doesn't exist */
1832 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
1833 ObjectIdGetDatum(opfmethod),
1834 CStringGetDatum(opfname),
1835 ObjectIdGetDatum(opfnamespace)))
1836 ereport(ERROR,
1838 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1839 opfname,
1840 get_am_name(opfmethod),
1841 get_namespace_name(opfnamespace))));
1842}

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum(), 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
180 htup = SearchSysCache3(CLAAMNAMENSP,
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);
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:2121
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:3385
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:3301

References 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
99 htup = SearchSysCache3(OPFAMILYAMNAMENSP,
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
112 htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
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);
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:2223

References DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT(), HeapTupleIsValid, LookupExplicitNamespace(), NameListToString(), NameStr, ObjectIdGetDatum(), OidIsValid, OpfamilynameGetOpfid(), 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(PointerIsAligned(start, uint64))
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183

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 {
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 &&
1453 SearchSysCacheExists4(AMOPSTRATEGY,
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,
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 if (typeDepNeeded(op->lefttype, op))
1512 {
1513 referenced.classId = TypeRelationId;
1514 referenced.objectId = op->lefttype;
1515 referenced.objectSubId = 0;
1516
1517 /* see comments in amapi.h about dependency strength */
1518 recordDependencyOn(&myself, &referenced,
1520 }
1521
1522 if (op->lefttype != op->righttype &&
1523 typeDepNeeded(op->righttype, op))
1524 {
1525 referenced.classId = TypeRelationId;
1526 referenced.objectId = op->righttype;
1527 referenced.objectSubId = 0;
1528
1529 /* see comments in amapi.h about dependency strength */
1530 recordDependencyOn(&myself, &referenced,
1532 }
1533
1534 /* A search operator also needs a dep on the referenced opfamily */
1535 if (OidIsValid(op->sortfamily))
1536 {
1537 referenced.classId = OperatorFamilyRelationId;
1538 referenced.objectId = op->sortfamily;
1539 referenced.objectSubId = 0;
1540
1541 recordDependencyOn(&myself, &referenced,
1543 }
1544
1545 /* Post create hook of this access method operator */
1546 InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1547 entryoid, 0);
1548 }
1549
1551}
@ DEPENDENCY_INTERNAL
Definition: dependency.h:35
static bool typeDepNeeded(Oid typid, OpFamilyMember *member)
Definition: opclasscmds.c:1675
static Datum CharGetDatum(char X)
Definition: postgres.h:127
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:106

References 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(), typeDepNeeded(), 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 1559 of file opclasscmds.c.

1561{
1562 Relation rel;
1563 Datum values[Natts_pg_amproc];
1564 bool nulls[Natts_pg_amproc];
1565 HeapTuple tup;
1566 Oid entryoid;
1567 ObjectAddress myself,
1568 referenced;
1569 ListCell *l;
1570
1571 rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1572
1573 foreach(l, procedures)
1574 {
1575 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1576
1577 /*
1578 * If adding to an existing family, check for conflict with an
1579 * existing pg_amproc entry (just to give a nicer error message)
1580 */
1581 if (isAdd &&
1582 SearchSysCacheExists4(AMPROCNUM,
1583 ObjectIdGetDatum(opfamilyoid),
1586 Int16GetDatum(proc->number)))
1587 ereport(ERROR,
1589 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1590 proc->number,
1591 format_type_be(proc->lefttype),
1593 NameListToString(opfamilyname))));
1594
1595 /* Create the pg_amproc entry */
1596 memset(values, 0, sizeof(values));
1597 memset(nulls, false, sizeof(nulls));
1598
1599 entryoid = GetNewOidWithIndex(rel, AccessMethodProcedureOidIndexId,
1600 Anum_pg_amproc_oid);
1601 values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1602 values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1603 values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1604 values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1605 values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1606 values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1607
1608 tup = heap_form_tuple(rel->rd_att, values, nulls);
1609
1610 CatalogTupleInsert(rel, tup);
1611
1612 heap_freetuple(tup);
1613
1614 /* Make its dependencies */
1615 myself.classId = AccessMethodProcedureRelationId;
1616 myself.objectId = entryoid;
1617 myself.objectSubId = 0;
1618
1619 referenced.classId = ProcedureRelationId;
1620 referenced.objectId = proc->object;
1621 referenced.objectSubId = 0;
1622
1623 /* see comments in amapi.h about dependency strength */
1624 recordDependencyOn(&myself, &referenced,
1626
1627 referenced.classId = proc->ref_is_family ? OperatorFamilyRelationId :
1628 OperatorClassRelationId;
1629 referenced.objectId = proc->refobjid;
1630 referenced.objectSubId = 0;
1631
1632 recordDependencyOn(&myself, &referenced,
1634
1635 if (typeDepNeeded(proc->lefttype, proc))
1636 {
1637 referenced.classId = TypeRelationId;
1638 referenced.objectId = proc->lefttype;
1639 referenced.objectSubId = 0;
1640
1641 /* see comments in amapi.h about dependency strength */
1642 recordDependencyOn(&myself, &referenced,
1644 }
1645
1646 if (proc->lefttype != proc->righttype &&
1647 typeDepNeeded(proc->righttype, proc))
1648 {
1649 referenced.classId = TypeRelationId;
1650 referenced.objectId = proc->righttype;
1651 referenced.objectSubId = 0;
1652
1653 /* see comments in amapi.h about dependency strength */
1654 recordDependencyOn(&myself, &referenced,
1656 }
1657
1658 /* Post create hook of access method procedure */
1659 InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1660 entryoid, 0);
1661 }
1662
1664}

References 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(), typeDepNeeded(), and values.

Referenced by AlterOpFamilyAdd(), and DefineOpClass().

◆ typeDepNeeded()

static bool typeDepNeeded ( Oid  typid,
OpFamilyMember member 
)
static

Definition at line 1675 of file opclasscmds.c.

1676{
1677 bool result = true;
1678
1679 /*
1680 * If the type is pinned, we don't need a dependency. This is a bit of a
1681 * layering violation perhaps (recordDependencyOn would ignore the request
1682 * anyway), but it's a cheap test and will frequently save a syscache
1683 * lookup here.
1684 */
1685 if (IsPinnedObject(TypeRelationId, typid))
1686 return false;
1687
1688 /* Nope, so check the input types of the function or operator. */
1689 if (member->is_func)
1690 {
1691 Oid *argtypes;
1692 int nargs;
1693
1694 (void) get_func_signature(member->object, &argtypes, &nargs);
1695 for (int i = 0; i < nargs; i++)
1696 {
1697 if (typid == argtypes[i])
1698 {
1699 result = false; /* match, no dependency needed */
1700 break;
1701 }
1702 }
1703 pfree(argtypes);
1704 }
1705 else
1706 {
1707 Oid lefttype,
1708 righttype;
1709
1710 op_input_types(member->object, &lefttype, &righttype);
1711 if (typid == lefttype || typid == righttype)
1712 result = false; /* match, no dependency needed */
1713 }
1714 return result;
1715}
bool IsPinnedObject(Oid classId, Oid objectId)
Definition: catalog.c:341
int i
Definition: isn.c:74
Oid get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
Definition: lsyscache.c:1779
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition: lsyscache.c:1441
void pfree(void *pointer)
Definition: mcxt.c:1524

References get_func_signature(), i, OpFamilyMember::is_func, IsPinnedObject(), OpFamilyMember::object, op_input_types(), and pfree().

Referenced by storeOperators(), and storeProcedures().