PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 1435 of file opclasscmds.c.

1436{
1437 ListCell *l;
1438
1439 foreach(l, *list)
1440 {
1442
1443 if (old->number == member->number &&
1444 old->lefttype == member->lefttype &&
1445 old->righttype == member->righttype)
1446 {
1447 if (member->is_func)
1448 ereport(ERROR,
1450 errmsg("function number %d for (%s,%s) appears more than once",
1451 member->number,
1452 format_type_be(member->lefttype),
1453 format_type_be(member->righttype))));
1454 else
1455 ereport(ERROR,
1457 errmsg("operator number %d for (%s,%s) appears more than once",
1458 member->number,
1459 format_type_be(member->lefttype),
1460 format_type_be(member->righttype))));
1461 }
1462 }
1463 *list = lappend(*list, member);
1464}
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
char * format_type_be(Oid type_oid)
List * lappend(List *list, void *datum)
Definition list.c:339
#define lfirst(lc)
Definition pg_list.h:172
static int fb(int x)
Oid lefttype
Definition amapi.h:93
Oid righttype
Definition amapi.h:94
bool is_func
Definition amapi.h:90

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

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

◆ AlterOpFamily()

Oid AlterOpFamily ( AlterOpFamilyStmt stmt)

Definition at line 837 of file opclasscmds.c.

838{
839 Oid amoid, /* our AM's oid */
840 opfamilyoid; /* oid of opfamily */
841 int maxOpNumber, /* amstrategies value */
842 optsProcNumber, /* amoptsprocnum value */
843 maxProcNumber; /* amsupport value */
847
848 /* Get necessary info about access method */
850 if (!HeapTupleIsValid(tup))
853 errmsg("access method \"%s\" does not exist",
854 stmt->amname)));
855
857 amoid = amform->oid;
860
861 maxOpNumber = amroutine->amstrategies;
862 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
863 if (maxOpNumber <= 0)
865 maxProcNumber = amroutine->amsupport;
866 optsProcNumber = amroutine->amoptsprocnum;
867
868 /* XXX Should we make any privilege check against the AM? */
869
870 /* Look up the opfamily */
871 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
872
873 /*
874 * Currently, we require superuser privileges to alter an opfamily.
875 *
876 * XXX re-enable NOT_USED code sections below if you remove this test.
877 */
878 if (!superuser())
881 errmsg("must be superuser to alter an operator family")));
882
883 /*
884 * ADD and DROP cases need separate code from here on down.
885 */
886 if (stmt->isDrop)
889 else
892 stmt->items);
893
894 return opfamilyoid;
895}
const IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition amapi.c:69
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int optsProcNumber, List *items)
FormData_pg_am * Form_pg_am
Definition pg_am.h:48
static Datum CStringGetDatum(const char *X)
Definition postgres.h:380
unsigned int Oid
bool superuser(void)
Definition superuser.c:46
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, fb(), 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 901 of file opclasscmds.c.

904{
906 List *operators; /* OpFamilyMember list for operators */
907 List *procedures; /* OpFamilyMember list for support procs */
908 ListCell *l;
909
910 operators = NIL;
911 procedures = NIL;
912
913 /*
914 * Scan the "items" list to obtain additional info.
915 */
916 foreach(l, items)
917 {
919 Oid operOid;
920 Oid funcOid;
922 OpFamilyMember *member;
923
924 switch (item->itemtype)
925 {
927 if (item->number <= 0 || item->number > maxOpNumber)
930 errmsg("invalid operator number %d,"
931 " must be between 1 and %d",
932 item->number, maxOpNumber)));
933 if (item->name->objargs != NIL)
934 operOid = LookupOperWithArgs(item->name, false);
935 else
936 {
939 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
940 operOid = InvalidOid; /* keep compiler quiet */
941 }
942
943 if (item->order_family)
945 item->order_family,
946 false);
947 else
949
950#ifdef NOT_USED
951 /* XXX this is unnecessary given the superuser check above */
952 /* Caller must own operator and its underlying function */
956 funcOid = get_opcode(operOid);
959 get_func_name(funcOid));
960#endif
961
962 /* Save the info */
964 member->is_func = false;
965 member->object = operOid;
966 member->number = item->number;
967 member->sortfamily = sortfamilyOid;
968 /* We can set up dependency fields immediately */
969 /* Historically, ALTER ADD has created soft dependencies */
970 member->ref_is_hard = false;
971 member->ref_is_family = true;
972 member->refobjid = opfamilyoid;
974 addFamilyMember(&operators, member);
975 break;
977 if (item->number <= 0 || item->number > maxProcNumber)
980 errmsg("invalid function number %d,"
981 " must be between 1 and %d",
982 item->number, maxProcNumber)));
983 funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
984#ifdef NOT_USED
985 /* XXX this is unnecessary given the superuser check above */
986 /* Caller must own function */
989 get_func_name(funcOid));
990#endif
991
992 /* Save the info */
994 member->is_func = true;
995 member->object = funcOid;
996 member->number = item->number;
997 /* We can set up dependency fields immediately */
998 /* Historically, ALTER ADD has created soft dependencies */
999 member->ref_is_hard = false;
1000 member->ref_is_family = true;
1001 member->refobjid = opfamilyoid;
1002
1003 /* allow overriding of the function's actual arg types */
1004 if (item->class_args)
1006 &member->lefttype, &member->righttype);
1007
1009 addFamilyMember(&procedures, member);
1010 break;
1012 ereport(ERROR,
1014 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
1015 break;
1016 default:
1017 elog(ERROR, "unrecognized item type: %d", item->itemtype);
1018 break;
1019 }
1020 }
1021
1022 /*
1023 * Let the index AM editorialize on the dependency choices. It could also
1024 * do further validation on the operators and functions, if it likes.
1025 */
1026 if (amroutine->amadjustmembers)
1027 amroutine->amadjustmembers(opfamilyoid,
1028 InvalidOid, /* no specific opclass */
1029 operators,
1030 procedures);
1031
1032 /*
1033 * Add tuples to pg_amop and pg_amproc tying in the operators and
1034 * functions. Dependencies on them are inserted, too.
1035 */
1036 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
1037 operators, true);
1038 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
1039 procedures, true);
1040
1041 /* make information available to event triggers */
1043 operators, procedures);
1044}
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4090
#define elog(elevel,...)
Definition elog.h:226
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
#define palloc0_object(type)
Definition fe_memutils.h:75
char * get_opname(Oid opno)
Definition lsyscache.c:1460
RegProcedure get_opcode(Oid opno)
Definition lsyscache.c:1435
char * get_func_name(Oid funcid)
Definition lsyscache.c:1758
Oid GetUserId(void)
Definition miscinit.c:469
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures, bool isAdd)
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators, bool isAdd)
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
static void addFamilyMember(List **list, OpFamilyMember *member)
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition parse_oper.c:134
#define OPCLASS_ITEM_STORAGETYPE
#define OPCLASS_ITEM_OPERATOR
#define OPCLASS_ITEM_FUNCTION
@ OBJECT_OPERATOR
@ OBJECT_FUNCTION
#define lfirst_node(type, lc)
Definition pg_list.h:176
#define NIL
Definition pg_list.h:68
#define InvalidOid
ObjectWithArgs * name
Definition pg_list.h:54
Oid refobjid
Definition amapi.h:98
bool ref_is_family
Definition amapi.h:97
bool ref_is_hard
Definition amapi.h:96
Oid sortfamily
Definition amapi.h:95
static ItemArray items

References aclcheck_error(), ACLCHECK_NOT_OWNER, addFamilyMember(), assignOperTypes(), assignProcTypes(), CreateOpClassItem::class_args, elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), fb(), 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_object, 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 1050 of file opclasscmds.c.

1052{
1053 List *operators; /* OpFamilyMember list for operators */
1054 List *procedures; /* OpFamilyMember list for support procs */
1055 ListCell *l;
1056
1057 operators = NIL;
1058 procedures = NIL;
1059
1060 /*
1061 * Scan the "items" list to obtain additional info.
1062 */
1063 foreach(l, items)
1064 {
1066 Oid lefttype,
1067 righttype;
1068 OpFamilyMember *member;
1069
1070 switch (item->itemtype)
1071 {
1073 if (item->number <= 0 || item->number > maxOpNumber)
1074 ereport(ERROR,
1076 errmsg("invalid operator number %d,"
1077 " must be between 1 and %d",
1078 item->number, maxOpNumber)));
1079 processTypesSpec(item->class_args, &lefttype, &righttype);
1080 /* Save the info */
1082 member->is_func = false;
1083 member->number = item->number;
1084 member->lefttype = lefttype;
1085 member->righttype = righttype;
1086 addFamilyMember(&operators, member);
1087 break;
1089 if (item->number <= 0 || item->number > maxProcNumber)
1090 ereport(ERROR,
1092 errmsg("invalid function number %d,"
1093 " must be between 1 and %d",
1094 item->number, maxProcNumber)));
1095 processTypesSpec(item->class_args, &lefttype, &righttype);
1096 /* Save the info */
1098 member->is_func = true;
1099 member->number = item->number;
1100 member->lefttype = lefttype;
1101 member->righttype = righttype;
1102 addFamilyMember(&procedures, member);
1103 break;
1105 /* grammar prevents this from appearing */
1106 default:
1107 elog(ERROR, "unrecognized item type: %d", item->itemtype);
1108 break;
1109 }
1110 }
1111
1112 /*
1113 * Remove tuples from pg_amop and pg_amproc.
1114 */
1115 dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1116 dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1117
1118 /* make information available to event triggers */
1120 operators, procedures);
1121}
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)

References addFamilyMember(), CreateOpClassItem::class_args, dropOperators(), dropProcedures(), elog, ereport, errcode(), errmsg(), ERROR, EventTriggerCollectAlterOpFam(), fb(), 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_object, processTypesSpec(), OpFamilyMember::righttype, and stmt.

Referenced by AlterOpFamily().

◆ assignOperTypes()

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

Definition at line 1157 of file opclasscmds.c.

1158{
1161
1162 /* Fetch the operator definition */
1164 if (!HeapTupleIsValid(optup))
1165 elog(ERROR, "cache lookup failed for operator %u", member->object);
1167
1168 /*
1169 * Opfamily operators must be binary.
1170 */
1171 if (opform->oprkind != 'b')
1172 ereport(ERROR,
1174 errmsg("index operators must be binary")));
1175
1176 if (OidIsValid(member->sortfamily))
1177 {
1178 /*
1179 * Ordering op, check index supports that. (We could perhaps also
1180 * check that the operator returns a type supported by the sortfamily,
1181 * but that seems more trouble than it's worth here. If it does not,
1182 * the operator will never be matchable to any ORDER BY clause, but no
1183 * worse consequences can ensue. Also, trying to check that would
1184 * create an ordering hazard during dump/reload: it's possible that
1185 * the family has been created but not yet populated with the required
1186 * operators.)
1187 */
1188 if (!GetIndexAmRoutineByAmId(amoid, false)->amcanorderbyop)
1189 ereport(ERROR,
1191 errmsg("access method \"%s\" does not support ordering operators",
1192 get_am_name(amoid))));
1193 }
1194 else
1195 {
1196 /*
1197 * Search operators must return boolean.
1198 */
1199 if (opform->oprresult != BOOLOID)
1200 ereport(ERROR,
1202 errmsg("index search operators must return boolean")));
1203 }
1204
1205 /*
1206 * If lefttype/righttype isn't specified, use the operator's input types
1207 */
1208 if (!OidIsValid(member->lefttype))
1209 member->lefttype = opform->oprleft;
1210 if (!OidIsValid(member->righttype))
1211 member->righttype = opform->oprright;
1212
1214}
char * get_am_name(Oid amOid)
Definition amcmds.c:192
#define OidIsValid(objectId)
Definition c.h:788
FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:83
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262

References elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 1221 of file opclasscmds.c.

1223{
1226
1227 /* Fetch the procedure definition */
1230 elog(ERROR, "cache lookup failed for function %u", member->object);
1232
1233 /* Check the signature of the opclass options parsing function */
1234 if (member->number == opclassOptsProcNum)
1235 {
1236 if (OidIsValid(typeoid))
1237 {
1238 if ((OidIsValid(member->lefttype) && member->lefttype != typeoid) ||
1239 (OidIsValid(member->righttype) && member->righttype != typeoid))
1240 ereport(ERROR,
1242 errmsg("associated data types for operator class options parsing functions must match opclass input type")));
1243 }
1244 else
1245 {
1246 if (member->lefttype != member->righttype)
1247 ereport(ERROR,
1249 errmsg("left and right associated data types for operator class options parsing functions must match")));
1250 }
1251
1252 if (procform->prorettype != VOIDOID ||
1253 procform->pronargs != 1 ||
1254 procform->proargtypes.values[0] != INTERNALOID)
1255 ereport(ERROR,
1257 errmsg("invalid operator class options parsing function"),
1258 errhint("Valid signature of operator class options parsing function is %s.",
1259 "(internal) RETURNS void")));
1260 }
1261
1262 /*
1263 * Ordering comparison procs must be 2-arg procs returning int4. Ordering
1264 * sortsupport procs must take internal and return void. Ordering
1265 * in_range procs must be 5-arg procs returning bool. Ordering equalimage
1266 * procs must take 1 arg and return bool. Hashing support proc 1 must be
1267 * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
1268 * returning int8. Otherwise we don't know.
1269 */
1270 else if (GetIndexAmRoutineByAmId(amoid, false)->amcanorder)
1271 {
1272 if (member->number == BTORDER_PROC)
1273 {
1274 if (procform->pronargs != 2)
1275 ereport(ERROR,
1277 errmsg("ordering comparison functions must have two arguments")));
1278 if (procform->prorettype != INT4OID)
1279 ereport(ERROR,
1281 errmsg("ordering comparison functions must return integer")));
1282
1283 /*
1284 * If lefttype/righttype isn't specified, use the proc's input
1285 * types
1286 */
1287 if (!OidIsValid(member->lefttype))
1288 member->lefttype = procform->proargtypes.values[0];
1289 if (!OidIsValid(member->righttype))
1290 member->righttype = procform->proargtypes.values[1];
1291 }
1292 else if (member->number == BTSORTSUPPORT_PROC)
1293 {
1294 if (procform->pronargs != 1 ||
1295 procform->proargtypes.values[0] != INTERNALOID)
1296 ereport(ERROR,
1298 errmsg("ordering sort support functions must accept type \"internal\"")));
1299 if (procform->prorettype != VOIDOID)
1300 ereport(ERROR,
1302 errmsg("ordering sort support functions must return void")));
1303
1304 /*
1305 * Can't infer lefttype/righttype from proc, so use default rule
1306 */
1307 }
1308 else if (member->number == BTINRANGE_PROC)
1309 {
1310 if (procform->pronargs != 5)
1311 ereport(ERROR,
1313 errmsg("ordering in_range functions must have five arguments")));
1314 if (procform->prorettype != BOOLOID)
1315 ereport(ERROR,
1317 errmsg("ordering in_range functions must return boolean")));
1318
1319 /*
1320 * If lefttype/righttype isn't specified, use the proc's input
1321 * types (we look at the test-value and offset arguments)
1322 */
1323 if (!OidIsValid(member->lefttype))
1324 member->lefttype = procform->proargtypes.values[0];
1325 if (!OidIsValid(member->righttype))
1326 member->righttype = procform->proargtypes.values[2];
1327 }
1328 else if (member->number == BTEQUALIMAGE_PROC)
1329 {
1330 if (procform->pronargs != 1)
1331 ereport(ERROR,
1333 errmsg("ordering equal image functions must have one argument")));
1334 if (procform->prorettype != BOOLOID)
1335 ereport(ERROR,
1337 errmsg("ordering equal image functions must return boolean")));
1338
1339 /*
1340 * pg_amproc functions are indexed by (lefttype, righttype), but
1341 * an equalimage function can only be called at CREATE INDEX time.
1342 * The same opclass opcintype OID is always used for lefttype and
1343 * righttype. Providing a cross-type routine isn't sensible.
1344 * Reject cross-type ALTER OPERATOR FAMILY ... ADD FUNCTION 4
1345 * statements here.
1346 */
1347 if (member->lefttype != member->righttype)
1348 ereport(ERROR,
1350 errmsg("ordering equal image functions must not be cross-type")));
1351 }
1352 else if (member->number == BTSKIPSUPPORT_PROC)
1353 {
1354 if (procform->pronargs != 1 ||
1355 procform->proargtypes.values[0] != INTERNALOID)
1356 ereport(ERROR,
1358 errmsg("btree skip support functions must accept type \"internal\"")));
1359 if (procform->prorettype != VOIDOID)
1360 ereport(ERROR,
1362 errmsg("btree skip support functions must return void")));
1363
1364 /*
1365 * pg_amproc functions are indexed by (lefttype, righttype), but a
1366 * skip support function doesn't make sense in cross-type
1367 * scenarios. The same opclass opcintype OID is always used for
1368 * lefttype and righttype. Providing a cross-type routine isn't
1369 * sensible. Reject cross-type ALTER OPERATOR FAMILY ... ADD
1370 * FUNCTION 6 statements here.
1371 */
1372 if (member->lefttype != member->righttype)
1373 ereport(ERROR,
1375 errmsg("btree skip support functions must not be cross-type")));
1376 }
1377 }
1378 else if (GetIndexAmRoutineByAmId(amoid, false)->amcanhash)
1379 {
1380 if (member->number == HASHSTANDARD_PROC)
1381 {
1382 if (procform->pronargs != 1)
1383 ereport(ERROR,
1385 errmsg("hash function 1 must have one argument")));
1386 if (procform->prorettype != INT4OID)
1387 ereport(ERROR,
1389 errmsg("hash function 1 must return integer")));
1390 }
1391 else if (member->number == HASHEXTENDED_PROC)
1392 {
1393 if (procform->pronargs != 2)
1394 ereport(ERROR,
1396 errmsg("hash function 2 must have two arguments")));
1397 if (procform->prorettype != INT8OID)
1398 ereport(ERROR,
1400 errmsg("hash function 2 must return bigint")));
1401 }
1402
1403 /*
1404 * If lefttype/righttype isn't specified, use the proc's input type
1405 */
1406 if (!OidIsValid(member->lefttype))
1407 member->lefttype = procform->proargtypes.values[0];
1408 if (!OidIsValid(member->righttype))
1409 member->righttype = procform->proargtypes.values[0];
1410 }
1411
1412 /*
1413 * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1414 * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1415 * isn't available, so make the user specify the types.
1416 */
1417 if (!OidIsValid(member->lefttype))
1418 member->lefttype = typeoid;
1419 if (!OidIsValid(member->righttype))
1420 member->righttype = typeoid;
1421
1422 if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1423 ereport(ERROR,
1425 errmsg("associated data types must be specified for index support function")));
1426
1428}
int errhint(const char *fmt,...)
Definition elog.c:1330
#define HASHSTANDARD_PROC
Definition hash.h:355
#define HASHEXTENDED_PROC
Definition hash.h:356
#define BTEQUALIMAGE_PROC
Definition nbtree.h:720
#define BTORDER_PROC
Definition nbtree.h:717
#define BTSKIPSUPPORT_PROC
Definition nbtree.h:722
#define BTSORTSUPPORT_PROC
Definition nbtree.h:718
#define BTINRANGE_PROC
Definition nbtree.h:719
FormData_pg_proc * Form_pg_proc
Definition pg_proc.h:136

References BTEQUALIMAGE_PROC, BTINRANGE_PROC, BTORDER_PROC, BTSKIPSUPPORT_PROC, BTSORTSUPPORT_PROC, elog, ereport, errcode(), errhint(), errmsg(), ERROR, fb(), 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{
247 Relation rel;
250 bool nulls[Natts_pg_opfamily];
254
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 */
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
284
285 tup = heap_form_tuple(rel->rd_att, values, nulls);
286
288
290
291 /*
292 * Create dependencies for the opfamily proper.
293 */
295 myself.objectId = opfamilyoid;
296 myself.objectSubId = 0;
297
298 /* dependency on access method */
300 referenced.objectId = amoid;
301 referenced.objectSubId = 0;
303
304 /* dependency on namespace */
306 referenced.objectId = namespaceoid;
307 referenced.objectSubId = 0;
309
310 /* dependency on owner */
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 */
322
324
325 return myself;
326}
static Datum values[MAXATTR]
Definition bootstrap.c:155
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
@ 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)
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)
static Datum NameGetDatum(const NameData *X)
Definition postgres.h:403
uint64_t Datum
Definition postgres.h:70
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
Definition nodes.h:135
TupleDesc rd_att
Definition rel.h:112
Definition c.h:760
#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(), CStringGetDatum(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, EventTriggerCollectSimpleCommand(), fb(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvalidObjectAddress, InvokeObjectPostCreateHook, NameGetDatum(), namestrcpy(), ObjectIdGetDatum(), 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 bool isDefault = stmt->isDefault;
347 List *operators; /* OpFamilyMember list for operators */
348 List *procedures; /* OpFamilyMember list for support procs */
349 ListCell *l;
350 Relation rel;
355 bool nulls[Natts_pg_opclass];
360
361 /* Convert list of names to a name and namespace */
363 &opcname);
364
365 /* Check we have creation rights in target namespace */
367 if (aclresult != ACLCHECK_OK)
370
371 /* Get necessary info about access method */
373 if (!HeapTupleIsValid(tup))
376 errmsg("access method \"%s\" does not exist",
377 stmt->amname)));
378
380 amoid = amform->oid;
383
384 maxOpNumber = amroutine->amstrategies;
385 /* if amstrategies is zero, just enforce that op numbers fit in int16 */
386 if (maxOpNumber <= 0)
388 maxProcNumber = amroutine->amsupport;
389 optsProcNumber = amroutine->amoptsprocnum;
390 amstorage = amroutine->amstorage;
391
392 /* XXX Should we make any privilege check against the AM? */
393
394 /*
395 * The question of appropriate permissions for CREATE OPERATOR CLASS is
396 * interesting. Creating an opclass is tantamount to granting public
397 * execute access on the functions involved, since the index machinery
398 * generally does not check access permission before using the functions.
399 * A minimum expectation therefore is that the caller have execute
400 * privilege with grant option. Since we don't have a way to make the
401 * opclass go away if the grant option is revoked, we choose instead to
402 * require ownership of the functions. It's also not entirely clear what
403 * permissions should be required on the datatype, but ownership seems
404 * like a safe choice.
405 *
406 * Currently, we require superuser privileges to create an opclass. This
407 * seems necessary because we have no way to validate that the offered set
408 * of operators and functions are consistent with the AM's expectations.
409 * It would be nice to provide such a check someday, if it can be done
410 * without solving the halting problem :-(
411 *
412 * XXX re-enable NOT_USED code sections below if you remove this test.
413 */
414 if (!superuser())
417 errmsg("must be superuser to create an operator class")));
418
419 /* Look up the datatype */
420 typeoid = typenameTypeId(NULL, stmt->datatype);
421
422#ifdef NOT_USED
423 /* XXX this is unnecessary given the superuser check above */
424 /* Check we have ownership of the datatype */
427#endif
428
429 /*
430 * Look up the containing operator family, or create one if FAMILY option
431 * was omitted and there's not a match already.
432 */
433 if (stmt->opfamilyname)
434 {
435 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
436 }
437 else
438 {
439 /* Lookup existing family of same name and namespace */
445 {
447
448 /*
449 * XXX given the superuser check above, there's no need for an
450 * ownership check here
451 */
453 }
454 else
455 {
458
460 opfstmt->opfamilyname = stmt->opclassname;
461 opfstmt->amname = stmt->amname;
462
463 /*
464 * Create it ... again no need for more permissions ...
465 */
467 opfamilyoid = tmpAddr.objectId;
468 }
469 }
470
471 operators = NIL;
472 procedures = NIL;
473
474 /* Storage datatype is optional */
476
477 /*
478 * Scan the "items" list to obtain additional info.
479 */
480 foreach(l, stmt->items)
481 {
483 Oid operOid;
484 Oid funcOid;
486 OpFamilyMember *member;
487
488 switch (item->itemtype)
489 {
491 if (item->number <= 0 || item->number > maxOpNumber)
494 errmsg("invalid operator number %d,"
495 " must be between 1 and %d",
496 item->number, maxOpNumber)));
497 if (item->name->objargs != NIL)
498 operOid = LookupOperWithArgs(item->name, false);
499 else
500 {
501 /* Default to binary op on input datatype */
504 false, -1);
505 }
506
507 if (item->order_family)
509 item->order_family,
510 false);
511 else
513
514#ifdef NOT_USED
515 /* XXX this is unnecessary given the superuser check above */
516 /* Caller must own operator and its underlying function */
520 funcOid = get_opcode(operOid);
523 get_func_name(funcOid));
524#endif
525
526 /* Save the info */
528 member->is_func = false;
529 member->object = operOid;
530 member->number = item->number;
531 member->sortfamily = sortfamilyOid;
532 assignOperTypes(member, amoid, typeoid);
533 addFamilyMember(&operators, member);
534 break;
536 if (item->number <= 0 || item->number > maxProcNumber)
539 errmsg("invalid function number %d,"
540 " must be between 1 and %d",
541 item->number, maxProcNumber)));
542 funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
543#ifdef NOT_USED
544 /* XXX this is unnecessary given the superuser check above */
545 /* Caller must own function */
548 get_func_name(funcOid));
549#endif
550 /* Save the info */
552 member->is_func = true;
553 member->object = funcOid;
554 member->number = item->number;
555
556 /* allow overriding of the function's actual arg types */
557 if (item->class_args)
559 &member->lefttype, &member->righttype);
560
562 addFamilyMember(&procedures, member);
563 break;
568 errmsg("storage type specified more than once")));
570
571#ifdef NOT_USED
572 /* XXX this is unnecessary given the superuser check above */
573 /* Check we have ownership of the datatype */
576#endif
577 break;
578 default:
579 elog(ERROR, "unrecognized item type: %d", item->itemtype);
580 break;
581 }
582 }
583
584 /*
585 * If storagetype is specified, make sure it's legal.
586 */
588 {
589 /* Just drop the spec if same as column datatype */
590 if (storageoid == typeoid)
592 else if (!amstorage)
595 errmsg("storage type cannot be different from data type for access method \"%s\"",
596 stmt->amname)));
597 }
598
600
601 /*
602 * Make sure there is no existing opclass of this name (this is just to
603 * give a more friendly error message than "duplicate key").
604 */
611 errmsg("operator class \"%s\" for access method \"%s\" already exists",
612 opcname, stmt->amname)));
613
614 /*
615 * HACK: if we're trying to create btree_gist's gist_inet_ops or
616 * gist_cidr_ops during a binary upgrade, avoid failure in the next stanza
617 * by silently making the new opclass non-default. Without this kluge, we
618 * would fail to upgrade databases containing pre-1.9 versions of
619 * contrib/btree_gist. We can remove it sometime in the far future when
620 * we don't expect any such databases to exist. (The result of this hack
621 * is that the installed version of btree_gist will approximate btree_gist
622 * 1.9, how closely depending on whether it's 1.8 or something older.
623 * ALTER EXTENSION UPDATE can be used to bring it up to real 1.9.)
624 */
625 if (isDefault && IsBinaryUpgrade)
626 {
627 if (amoid == GIST_AM_OID &&
628 ((typeoid == INETOID && strcmp(opcname, "gist_inet_ops") == 0) ||
629 (typeoid == CIDROID && strcmp(opcname, "gist_cidr_ops") == 0)))
630 isDefault = false;
631 }
632
633 /*
634 * If we are creating a default opclass, check there isn't one already.
635 * (Note we do not restrict this test to visible opclasses; this ensures
636 * that typcache.c can find unique solutions to its questions.)
637 */
638 if (isDefault)
639 {
640 ScanKeyData skey[1];
641 SysScanDesc scan;
642
643 ScanKeyInit(&skey[0],
647
649 NULL, 1, skey);
650
651 while (HeapTupleIsValid(tup = systable_getnext(scan)))
652 {
654
655 if (opclass->opcintype == typeoid && opclass->opcdefault)
658 errmsg("could not make operator class \"%s\" be default for type %s",
659 opcname,
660 TypeNameToString(stmt->datatype)),
661 errdetail("Operator class \"%s\" already is the default.",
662 NameStr(opclass->opcname))));
663 }
664
665 systable_endscan(scan);
666 }
667
668 /*
669 * Okay, let's create the pg_opclass entry.
670 */
671 memset(values, 0, sizeof(values));
672 memset(nulls, false, sizeof(nulls));
673
674 opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
686
687 tup = heap_form_tuple(rel->rd_att, values, nulls);
688
690
692
693 /*
694 * Now that we have the opclass OID, set up default dependency info for
695 * the pg_amop and pg_amproc entries. Historically, CREATE OPERATOR CLASS
696 * has created hard dependencies on the opclass, so that's what we use.
697 */
698 foreach(l, operators)
699 {
701
702 op->ref_is_hard = true;
703 op->ref_is_family = false;
704 op->refobjid = opclassoid;
705 }
706 foreach(l, procedures)
707 {
708 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
709
710 proc->ref_is_hard = true;
711 proc->ref_is_family = false;
712 proc->refobjid = opclassoid;
713 }
714
715 /*
716 * Let the index AM editorialize on the dependency choices. It could also
717 * do further validation on the operators and functions, if it likes.
718 */
719 if (amroutine->amadjustmembers)
720 amroutine->amadjustmembers(opfamilyoid,
721 opclassoid,
722 operators,
723 procedures);
724
725 /*
726 * Now add tuples to pg_amop and pg_amproc tying in the operators and
727 * functions. Dependencies on them are inserted, too.
728 */
729 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
730 operators, false);
731 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
732 procedures, false);
733
734 /* let event triggers know what happened */
735 EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
736
737 /*
738 * Create dependencies for the opclass proper. Note: we do not need a
739 * dependency link to the AM, because that exists through the opfamily.
740 */
742 myself.objectId = opclassoid;
743 myself.objectSubId = 0;
744
745 /* dependency on namespace */
747 referenced.objectId = namespaceoid;
748 referenced.objectSubId = 0;
750
751 /* dependency on opfamily */
753 referenced.objectId = opfamilyoid;
754 referenced.objectSubId = 0;
756
757 /* dependency on indexed datatype */
758 referenced.classId = TypeRelationId;
759 referenced.objectId = typeoid;
760 referenced.objectSubId = 0;
762
763 /* dependency on storage datatype */
765 {
766 referenced.classId = TypeRelationId;
767 referenced.objectId = storageoid;
768 referenced.objectSubId = 0;
770 }
771
772 /* dependency on owner */
774
775 /* dependency on extension */
777
778 /* Post creation hook for new operator class */
780
782
783 return myself;
784}
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:3836
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition aclchk.c:2973
#define NameStr(name)
Definition c.h:765
int errdetail(const char *fmt,...)
Definition elog.c:1216
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
bool IsBinaryUpgrade
Definition globals.c:121
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3557
#define makeNode(_type_)
Definition nodes.h:161
static ObjectAddress CreateOpFamily(CreateOpFamilyStmt *stmt, const char *opfname, Oid namespaceoid, Oid amoid)
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition parse_oper.c:100
char * TypeNameToString(const TypeName *typeName)
Definition parse_type.c:478
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
@ OBJECT_SCHEMA
#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:352
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
#define BTEqualStrategyNumber
Definition stratnum.h:31
TypeName * storedtype
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition syscache.c:240

References ACL_CREATE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), assignOperTypes(), assignProcTypes(), BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleInsert(), CreateOpClassItem::class_args, CreateOpFamily(), CStringGetDatum(), DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errdetail(), errmsg(), ERROR, EventTriggerCollectCreateOpClass(), fb(), 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, IsBinaryUpgrade, 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, ObjectIdGetDatum(), ObjectWithArgs::objname, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, CreateOpClassItem::order_family, palloc0_object, 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 792 of file opclasscmds.c.

793{
794 char *opfname; /* name of opfamily we're creating */
795 Oid amoid, /* our AM's oid */
796 namespaceoid; /* namespace to create opfamily in */
798
799 /* Convert list of names to a name and namespace */
801 &opfname);
802
803 /* Check we have creation rights in target namespace */
805 if (aclresult != ACLCHECK_OK)
808
809 /* Get access method OID, throwing an error if it doesn't exist. */
810 amoid = get_index_am_oid(stmt->amname, false);
811
812 /* XXX Should we make any privilege check against the AM? */
813
814 /*
815 * Currently, we require superuser privileges to create an opfamily. See
816 * comments in DefineOpClass.
817 */
818 if (!superuser())
821 errmsg("must be superuser to create an operator family")));
822
823 /* Insert pg_opfamily catalog entry */
825}
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, fb(), 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 1768 of file opclasscmds.c.

1770{
1771 ListCell *l;
1772
1773 foreach(l, operators)
1774 {
1776 Oid amopid;
1777 ObjectAddress object;
1778
1783 Int16GetDatum(op->number));
1784 if (!OidIsValid(amopid))
1785 ereport(ERROR,
1787 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1788 op->number,
1791 NameListToString(opfamilyname))));
1792
1793 object.classId = AccessMethodOperatorRelationId;
1794 object.objectId = amopid;
1795 object.objectSubId = 0;
1796
1797 performDeletion(&object, DROP_RESTRICT, 0);
1798 }
1799}
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition dependency.c:274
char * NameListToString(const List *names)
Definition namespace.c:3664
@ DROP_RESTRICT
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition syscache.h:115

References DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, fb(), 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 1808 of file opclasscmds.c.

1810{
1811 ListCell *l;
1812
1813 foreach(l, procedures)
1814 {
1816 Oid amprocid;
1817 ObjectAddress object;
1818
1823 Int16GetDatum(op->number));
1824 if (!OidIsValid(amprocid))
1825 ereport(ERROR,
1827 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1828 op->number,
1831 NameListToString(opfamilyname))));
1832
1833 object.classId = AccessMethodProcedureRelationId;
1834 object.objectId = amprocid;
1835 object.objectSubId = 0;
1836
1837 performDeletion(&object, DROP_RESTRICT, 0);
1838 }
1839}

References DROP_RESTRICT, ereport, errcode(), errmsg(), ERROR, fb(), 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;
224 Oid opcID;
225
226 htup = OpClassCacheLookup(amID, opclassname, missing_ok);
227 if (!HeapTupleIsValid(htup))
228 return InvalidOid;
230 opcID = opcform->oid;
231 ReleaseSysCache(htup);
232
233 return opcID;
234}
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)

References fb(), 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;
143 Oid opfID;
144
145 htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
146 if (!HeapTupleIsValid(htup))
147 return InvalidOid;
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 fb(), 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 1848 of file opclasscmds.c.

1850{
1851 /* make sure the new name doesn't exist */
1853 ObjectIdGetDatum(opcmethod),
1856 ereport(ERROR,
1858 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1859 opcname,
1860 get_am_name(opcmethod),
1862}

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fb(), 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 1871 of file opclasscmds.c.

1873{
1874 /* make sure the new name doesn't exist */
1876 ObjectIdGetDatum(opfmethod),
1879 ereport(ERROR,
1881 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1882 opfname,
1883 get_am_name(opfmethod),
1885}

References CStringGetDatum(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fb(), 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 */
175
176 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
178 htup = NULL;
179 else
184 }
185 else
186 {
187 /* Unqualified opclass name, so search the search path */
189
190 if (!OidIsValid(opcID))
191 htup = NULL;
192 else
194 }
195
196 if (!HeapTupleIsValid(htup) && !missing_ok)
197 {
199
202 elog(ERROR, "cache lookup failed for access method %u", amID);
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:2188
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition namespace.c:3455
void DeconstructQualifiedName(const List *names, char **nspname_p, char **objname_p)
Definition namespace.c:3371

References DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 */
94
95 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
97 htup = NULL;
98 else
103 }
104 else
105 {
106 /* Unqualified opfamily name, so search the search path */
108
109 if (!OidIsValid(opfID))
110 htup = NULL;
111 else
113 }
114
115 if (!HeapTupleIsValid(htup) && !missing_ok)
116 {
118
121 elog(ERROR, "cache lookup failed for access method %u", amID);
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:2290

References DeconstructQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, fb(), 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 1128 of file opclasscmds.c.

1129{
1130 TypeName *typeName;
1131
1132 Assert(args != NIL);
1133
1134 typeName = (TypeName *) linitial(args);
1135 *lefttype = typenameTypeId(NULL, typeName);
1136
1137 if (list_length(args) > 1)
1138 {
1139 typeName = (TypeName *) lsecond(args);
1140 *righttype = typenameTypeId(NULL, typeName);
1141 }
1142 else
1143 *righttype = *lefttype;
1144
1145 if (list_length(args) > 2)
1146 ereport(ERROR,
1148 errmsg("one or two argument types must be specified")));
1149}
#define Assert(condition)
Definition c.h:873
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 Assert, ereport, errcode(), errmsg(), ERROR, fb(), 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 1472 of file opclasscmds.c.

1474{
1475 Relation rel;
1477 bool nulls[Natts_pg_amop];
1478 HeapTuple tup;
1479 Oid entryoid;
1481 referenced;
1482 ListCell *l;
1483
1485
1486 foreach(l, operators)
1487 {
1489 char oppurpose;
1490
1491 /*
1492 * If adding to an existing family, check for conflict with an
1493 * existing pg_amop entry (just to give a nicer error message)
1494 */
1495 if (isAdd &&
1500 Int16GetDatum(op->number)))
1501 ereport(ERROR,
1503 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1504 op->number,
1507 NameListToString(opfamilyname))));
1508
1510
1511 /* Create the pg_amop entry */
1512 memset(values, 0, sizeof(values));
1513 memset(nulls, false, sizeof(nulls));
1514
1526
1527 tup = heap_form_tuple(rel->rd_att, values, nulls);
1528
1529 CatalogTupleInsert(rel, tup);
1530
1532
1533 /* Make its dependencies */
1535 myself.objectId = entryoid;
1536 myself.objectSubId = 0;
1537
1539 referenced.objectId = op->object;
1540 referenced.objectSubId = 0;
1541
1542 /* see comments in amapi.h about dependency strength */
1545
1548 referenced.objectId = op->refobjid;
1549 referenced.objectSubId = 0;
1550
1553
1554 if (typeDepNeeded(op->lefttype, op))
1555 {
1556 referenced.classId = TypeRelationId;
1557 referenced.objectId = op->lefttype;
1558 referenced.objectSubId = 0;
1559
1560 /* see comments in amapi.h about dependency strength */
1563 }
1564
1565 if (op->lefttype != op->righttype &&
1566 typeDepNeeded(op->righttype, op))
1567 {
1568 referenced.classId = TypeRelationId;
1569 referenced.objectId = op->righttype;
1570 referenced.objectSubId = 0;
1571
1572 /* see comments in amapi.h about dependency strength */
1575 }
1576
1577 /* A search operator also needs a dep on the referenced opfamily */
1578 if (OidIsValid(op->sortfamily))
1579 {
1581 referenced.objectId = op->sortfamily;
1582 referenced.objectSubId = 0;
1583
1586 }
1587
1588 /* Post create hook of this access method operator */
1590 entryoid, 0);
1591 }
1592
1594}
@ DEPENDENCY_INTERNAL
Definition dependency.h:35
static bool typeDepNeeded(Oid typid, OpFamilyMember *member)
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition syscache.h:106

References CatalogTupleInsert(), CharGetDatum(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fb(), format_type_be(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), Int16GetDatum(), InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectIdGetDatum(), 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 1602 of file opclasscmds.c.

1604{
1605 Relation rel;
1607 bool nulls[Natts_pg_amproc];
1608 HeapTuple tup;
1609 Oid entryoid;
1611 referenced;
1612 ListCell *l;
1613
1615
1616 foreach(l, procedures)
1617 {
1618 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1619
1620 /*
1621 * If adding to an existing family, check for conflict with an
1622 * existing pg_amproc entry (just to give a nicer error message)
1623 */
1624 if (isAdd &&
1629 Int16GetDatum(proc->number)))
1630 ereport(ERROR,
1632 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1633 proc->number,
1634 format_type_be(proc->lefttype),
1636 NameListToString(opfamilyname))));
1637
1638 /* Create the pg_amproc entry */
1639 memset(values, 0, sizeof(values));
1640 memset(nulls, false, sizeof(nulls));
1641
1650
1651 tup = heap_form_tuple(rel->rd_att, values, nulls);
1652
1653 CatalogTupleInsert(rel, tup);
1654
1656
1657 /* Make its dependencies */
1659 myself.objectId = entryoid;
1660 myself.objectSubId = 0;
1661
1663 referenced.objectId = proc->object;
1664 referenced.objectSubId = 0;
1665
1666 /* see comments in amapi.h about dependency strength */
1669
1672 referenced.objectId = proc->refobjid;
1673 referenced.objectSubId = 0;
1674
1677
1678 if (typeDepNeeded(proc->lefttype, proc))
1679 {
1680 referenced.classId = TypeRelationId;
1681 referenced.objectId = proc->lefttype;
1682 referenced.objectSubId = 0;
1683
1684 /* see comments in amapi.h about dependency strength */
1687 }
1688
1689 if (proc->lefttype != proc->righttype &&
1690 typeDepNeeded(proc->righttype, proc))
1691 {
1692 referenced.classId = TypeRelationId;
1693 referenced.objectId = proc->righttype;
1694 referenced.objectSubId = 0;
1695
1696 /* see comments in amapi.h about dependency strength */
1699 }
1700
1701 /* Post create hook of access method procedure */
1703 entryoid, 0);
1704 }
1705
1707}

References CatalogTupleInsert(), DEPENDENCY_AUTO, DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, fb(), format_type_be(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), Int16GetDatum(), InvokeObjectPostCreateHook, OpFamilyMember::lefttype, lfirst, NameListToString(), OpFamilyMember::number, OpFamilyMember::object, ObjectIdGetDatum(), 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 1718 of file opclasscmds.c.

1719{
1720 bool result = true;
1721
1722 /*
1723 * If the type is pinned, we don't need a dependency. This is a bit of a
1724 * layering violation perhaps (recordDependencyOn would ignore the request
1725 * anyway), but it's a cheap test and will frequently save a syscache
1726 * lookup here.
1727 */
1728 if (IsPinnedObject(TypeRelationId, typid))
1729 return false;
1730
1731 /* Nope, so check the input types of the function or operator. */
1732 if (member->is_func)
1733 {
1734 Oid *argtypes;
1735 int nargs;
1736
1737 (void) get_func_signature(member->object, &argtypes, &nargs);
1738 for (int i = 0; i < nargs; i++)
1739 {
1740 if (typid == argtypes[i])
1741 {
1742 result = false; /* match, no dependency needed */
1743 break;
1744 }
1745 }
1746 pfree(argtypes);
1747 }
1748 else
1749 {
1750 Oid lefttype,
1751 righttype;
1752
1753 op_input_types(member->object, &lefttype, &righttype);
1754 if (typid == lefttype || typid == righttype)
1755 result = false; /* match, no dependency needed */
1756 }
1757 return result;
1758}
bool IsPinnedObject(Oid classId, Oid objectId)
Definition catalog.c:370
int i
Definition isn.c:77
Oid get_func_signature(Oid funcid, Oid **argtypes, int *nargs)
Definition lsyscache.c:1846
void op_input_types(Oid opno, Oid *lefttype, Oid *righttype)
Definition lsyscache.c:1508
void pfree(void *pointer)
Definition mcxt.c:1616

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

Referenced by storeOperators(), and storeProcedures().