staticvoid AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int optsProcNumber, List *items); staticvoid AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber,
List *items); staticvoid processTypesSpec(List *args, Oid *lefttype, Oid *righttype); staticvoid assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid); staticvoid assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum); staticvoid addFamilyMember(List **list, OpFamilyMember *member); staticvoid storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators, bool isAdd); staticvoid storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures, bool isAdd); staticbool typeDepNeeded(Oid typid, OpFamilyMember *member); staticvoid dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *operators); staticvoid dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
List *procedures);
/* dependency on owner */
recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Report the new operator family to possibly interested event triggers */
EventTriggerCollectSimpleCommand(myself, InvalidObjectAddress,
(Node *) stmt);
/* Post creation hook for new operator family */
InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
table_close(rel, RowExclusiveLock);
return myself;
}
/* *DefineOpClass *Defineanewindexoperatorclass.
*/
ObjectAddress
DefineOpClass(CreateOpClassStmt *stmt)
{ char *opcname; /* name of opclass we're creating */
Oid amoid, /* our AM's oid */
typeoid, /* indexable datatype oid */
storageoid, /* storage datatype oid, if any */
namespaceoid, /* namespace to create opclass in */
opfamilyoid, /* oid of containing opfamily */
opclassoid; /* oid of opclass we create */ int maxOpNumber, /* amstrategies value */
optsProcNumber, /* amoptsprocnum value */
maxProcNumber; /* amsupport value */ bool amstorage; /* amstorage flag */
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
Relation rel;
HeapTuple tup;
Form_pg_am amform;
IndexAmRoutine *amroutine;
Datum values[Natts_pg_opclass]; bool nulls[Natts_pg_opclass];
AclResult aclresult;
NameData opcName;
ObjectAddress myself,
referenced;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
&opcname);
/* Check we have creation rights in target namespace */
aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_SCHEMA,
get_namespace_name(namespaceoid));
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname)); if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
maxOpNumber = amroutine->amstrategies; /* if amstrategies is zero, just enforce that op numbers fit in int16 */ if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = amroutine->amsupport;
optsProcNumber = amroutine->amoptsprocnum;
amstorage = amroutine->amstorage;
/* XXX Should we make any privilege check against the AM? */
/* *ThequestionofappropriatepermissionsforCREATEOPERATORCLASSis *interesting.Creatinganopclassistantamounttograntingpublic *executeaccessonthefunctionsinvolved,sincetheindexmachinery *generallydoesnotcheckaccesspermissionbeforeusingthefunctions. *Aminimumexpectationthereforeisthatthecallerhaveexecute *privilegewithgrantoption.Sincewedon'thaveawaytomakethe *opclassgoawayifthegrantoptionisrevoked,wechooseinsteadto *requireownershipofthefunctions.It'salsonotentirelyclearwhat *permissionsshouldberequiredonthedatatype,butownershipseems *likeasafechoice. * *Currently,werequiresuperuserprivilegestocreateanopclass.This *seemsnecessarybecausewehavenowaytovalidatethattheofferedset *ofoperatorsandfunctionsareconsistentwiththeAM'sexpectations. *Itwouldbenicetoprovidesuchachecksomeday,ifitcanbedone *withoutsolvingthehaltingproblem:-( * *XXXre-enableNOT_USEDcodesectionsbelowifyouremovethistest.
*/ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator class")));
/* Look up the datatype */
typeoid = typenameTypeId(NULL, stmt->datatype);
#ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Check we have ownership of the datatype */ if (!object_ownercheck(TypeRelationId, typeoid, GetUserId()))
aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid); #endif
/* *Lookupthecontainingoperatorfamily,orcreateoneifFAMILYoption *wasomittedandthere'snotamatchalready.
*/ if (stmt->opfamilyname)
{
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
} else
{ /* Lookup existing family of same name and namespace */
tup = SearchSysCache3(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(amoid),
PointerGetDatum(opcname),
ObjectIdGetDatum(namespaceoid)); if (HeapTupleIsValid(tup))
{
opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
#ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Caller must own operator and its underlying function */ if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
get_opname(operOid));
funcOid = get_opcode(operOid); if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
get_func_name(funcOid)); #endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = false;
member->object = operOid;
member->number = item->number;
member->sortfamily = sortfamilyOid;
assignOperTypes(member, amoid, typeoid);
addFamilyMember(&operators, member); break; case OPCLASS_ITEM_FUNCTION: if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid function number %d," " must be between 1 and %d",
item->number, maxProcNumber)));
funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Caller must own function */ if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
get_func_name(funcOid)); #endif /* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = true;
member->object = funcOid;
member->number = item->number;
/* allow overriding of the function's actual arg types */ if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, typeoid, optsProcNumber);
addFamilyMember(&procedures, member); break; case OPCLASS_ITEM_STORAGETYPE: if (OidIsValid(storageoid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type specified more than once")));
storageoid = typenameTypeId(NULL, item->storedtype);
#ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Check we have ownership of the datatype */ if (!object_ownercheck(TypeRelationId, storageoid, GetUserId()))
aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid); #endif break; default:
elog(ERROR, "unrecognized item type: %d", item->itemtype); break;
}
}
/* *Ifstoragetypeisspecified,makesureit'slegal.
*/ if (OidIsValid(storageoid))
{ /* Just drop the spec if same as column datatype */ if (storageoid == typeoid)
storageoid = InvalidOid; elseif (!amstorage)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("storage type cannot be different from data type for access method \"%s\"",
stmt->amname)));
}
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
if (opclass->opcintype == typeoid && opclass->opcdefault)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("could not make operator class \"%s\" be default for type %s",
opcname,
TypeNameToString(stmt->datatype)),
errdetail("Operator class \"%s\" already is the default.",
NameStr(opclass->opcname))));
}
/* dependency on owner */
recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
/* dependency on extension */
recordDependencyOnCurrentExtension(&myself, false);
/* Post creation hook for new operator class */
InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
table_close(rel, RowExclusiveLock);
return myself;
}
/* *DefineOpFamily *Defineanewindexoperatorfamily.
*/
ObjectAddress
DefineOpFamily(CreateOpFamilyStmt *stmt)
{ char *opfname; /* name of opfamily we're creating */
Oid amoid, /* our AM's oid */
namespaceoid; /* namespace to create opfamily in */
AclResult aclresult;
/* Convert list of names to a name and namespace */
namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
&opfname);
/* Check we have creation rights in target namespace */
aclresult = object_aclcheck(NamespaceRelationId, namespaceoid, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_SCHEMA,
get_namespace_name(namespaceoid));
/* Get access method OID, throwing an error if it doesn't exist. */
amoid = get_index_am_oid(stmt->amname, false);
/* XXX Should we make any privilege check against the AM? */
/* *Currently,werequiresuperuserprivilegestocreateanopfamily.See *commentsinDefineOpClass.
*/ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to create an operator family")));
/* *AlterOpFamily *Addorremoveoperators/procedureswithinanexistingoperatorfamily. * *Note:thisimplementsonlyALTEROPERATORFAMILY...ADD/DROP.Some *othercommandscalledALTEROPERATORFAMILYexist,butgothrough *differentcodepaths.
*/
Oid
AlterOpFamily(AlterOpFamilyStmt *stmt)
{
Oid amoid, /* our AM's oid */
opfamilyoid; /* oid of opfamily */ int maxOpNumber, /* amstrategies value */
optsProcNumber, /* amoptsprocnum value */
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am amform;
IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname)); if (!HeapTupleIsValid(tup))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("access method \"%s\" does not exist",
stmt->amname)));
maxOpNumber = amroutine->amstrategies; /* if amstrategies is zero, just enforce that op numbers fit in int16 */ if (maxOpNumber <= 0)
maxOpNumber = SHRT_MAX;
maxProcNumber = amroutine->amsupport;
optsProcNumber = amroutine->amoptsprocnum;
/* XXX Should we make any privilege check against the AM? */
/* Look up the opfamily */
opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
/* *Currently,werequiresuperuserprivilegestoalteranopfamily. * *XXXre-enableNOT_USEDcodesectionsbelowifyouremovethistest.
*/ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter an operator family")));
/* *ADDpartofALTEROPFAMILY
*/ staticvoid
AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, int optsProcNumber,
List *items)
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
operators = NIL;
procedures = NIL;
/* *Scanthe"items"listtoobtainadditionalinfo.
*/
foreach(l, items)
{
CreateOpClassItem *item = lfirst_node(CreateOpClassItem, l);
Oid operOid;
Oid funcOid;
Oid sortfamilyOid;
OpFamilyMember *member;
switch (item->itemtype)
{ case OPCLASS_ITEM_OPERATOR: if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d," " must be between 1 and %d",
item->number, maxOpNumber))); if (item->name->objargs != NIL)
operOid = LookupOperWithArgs(item->name, false); else
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
operOid = InvalidOid; /* keep compiler quiet */
}
#ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Caller must own operator and its underlying function */ if (!object_ownercheck(OperatorRelationId, operOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
get_opname(operOid));
funcOid = get_opcode(operOid); if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
get_func_name(funcOid)); #endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = false;
member->object = operOid;
member->number = item->number;
member->sortfamily = sortfamilyOid; /* We can set up dependency fields immediately */ /* Historically, ALTER ADD has created soft dependencies */
member->ref_is_hard = false;
member->ref_is_family = true;
member->refobjid = opfamilyoid;
assignOperTypes(member, amoid, InvalidOid);
addFamilyMember(&operators, member); break; case OPCLASS_ITEM_FUNCTION: if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid function number %d," " must be between 1 and %d",
item->number, maxProcNumber)));
funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false); #ifdef NOT_USED /* XXX this is unnecessary given the superuser check above */ /* Caller must own function */ if (!object_ownercheck(ProcedureRelationId, funcOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
get_func_name(funcOid)); #endif
/* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = true;
member->object = funcOid;
member->number = item->number; /* We can set up dependency fields immediately */ /* Historically, ALTER ADD has created soft dependencies */
member->ref_is_hard = false;
member->ref_is_family = true;
member->refobjid = opfamilyoid;
/* allow overriding of the function's actual arg types */ if (item->class_args)
processTypesSpec(item->class_args,
&member->lefttype, &member->righttype);
assignProcTypes(member, amoid, InvalidOid, optsProcNumber);
addFamilyMember(&procedures, member); break; case OPCLASS_ITEM_STORAGETYPE:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY"))); break; default:
elog(ERROR, "unrecognized item type: %d", item->itemtype); break;
}
}
/* *LettheindexAMeditorializeonthedependencychoices.Itcouldalso *dofurthervalidationontheoperatorsandfunctions,ifitlikes.
*/ if (amroutine->amadjustmembers)
amroutine->amadjustmembers(opfamilyoid,
InvalidOid, /* no specific opclass */
operators,
procedures);
/* make information available to event triggers */
EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
operators, procedures);
}
/* *DROPpartofALTEROPFAMILY
*/ staticvoid
AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
{
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
switch (item->itemtype)
{ case OPCLASS_ITEM_OPERATOR: if (item->number <= 0 || item->number > maxOpNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator number %d," " must be between 1 and %d",
item->number, maxOpNumber)));
processTypesSpec(item->class_args, &lefttype, &righttype); /* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = false;
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&operators, member); break; case OPCLASS_ITEM_FUNCTION: if (item->number <= 0 || item->number > maxProcNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid function number %d," " must be between 1 and %d",
item->number, maxProcNumber)));
processTypesSpec(item->class_args, &lefttype, &righttype); /* Save the info */
member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
member->is_func = true;
member->number = item->number;
member->lefttype = lefttype;
member->righttype = righttype;
addFamilyMember(&procedures, member); break; case OPCLASS_ITEM_STORAGETYPE: /* grammar prevents this from appearing */ default:
elog(ERROR, "unrecognized item type: %d", item->itemtype); break;
}
}
if (list_length(args) > 2)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("one or two argument types must be specified")));
}
/* *Determinethelefttype/righttypetoassigntoanoperator, *anddoanyvaliditycheckingwecanmanage.
*/ staticvoid
assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
{ Operator optup;
Form_pg_operator opform;
/* Fetch the operator definition */
optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object)); if (!HeapTupleIsValid(optup))
elog(ERROR, "cache lookup failed for operator %u", member->object);
opform = (Form_pg_operator) GETSTRUCT(optup);
/* *Opfamilyoperatorsmustbebinary.
*/ if (opform->oprkind != 'b')
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index operators must be binary")));
if (!amroutine->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",
get_am_name(amoid))));
} else
{ /* *Searchoperatorsmustreturnboolean.
*/ if (opform->oprresult != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index search operators must return boolean")));
}
/* *Iflefttype/righttypeisn'tspecified,usetheoperator'sinputtypes
*/ if (!OidIsValid(member->lefttype))
member->lefttype = opform->oprleft; if (!OidIsValid(member->righttype))
member->righttype = opform->oprright;
ReleaseSysCache(optup);
}
/* *Determinethelefttype/righttypetoassigntoasupportprocedure, *anddoanyvaliditycheckingwecanmanage.
*/ staticvoid
assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid, int opclassOptsProcNum)
{
HeapTuple proctup;
Form_pg_proc procform;
/* Fetch the procedure definition */
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object)); if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for function %u", member->object);
procform = (Form_pg_proc) GETSTRUCT(proctup);
/* Check the signature of the opclass options parsing function */ if (member->number == opclassOptsProcNum)
{ if (OidIsValid(typeoid))
{ if ((OidIsValid(member->lefttype) && member->lefttype != typeoid) ||
(OidIsValid(member->righttype) && member->righttype != typeoid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("associated data types for operator class options parsing functions must match opclass input type")));
} else
{ if (member->lefttype != member->righttype)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("left and right associated data types for operator class options parsing functions must match")));
}
if (procform->prorettype != VOIDOID ||
procform->pronargs != 1 ||
procform->proargtypes.values[0] != INTERNALOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("invalid operator class options parsing function"),
errhint("Valid signature of operator class options parsing function is %s.", "(internal) RETURNS void")));
}
/* *Orderingcomparisonprocsmustbe2-argprocsreturningint4.Ordering *sortsupportprocsmusttakeinternalandreturnvoid.Ordering *in_rangeprocsmustbe5-argprocsreturningbool.Orderingequalimage *procsmusttake1argandreturnbool.Hashingsupportproc1mustbe *a1-argprocreturningint4,whileproc2mustbea2-argproc *returningint8.Otherwisewedon'tknow.
*/ elseif (GetIndexAmRoutineByAmId(amoid, false)->amcanorder)
{ if (member->number == BTORDER_PROC)
{ if (procform->pronargs != 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering comparison functions must have two arguments"))); if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering comparison functions must return integer")));
/* *Iflefttype/righttypeisn'tspecified,usetheproc'sinput *types
*/ if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0]; if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[1];
} elseif (member->number == BTSORTSUPPORT_PROC)
{ if (procform->pronargs != 1 ||
procform->proargtypes.values[0] != INTERNALOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering sort support functions must accept type \"internal\""))); if (procform->prorettype != VOIDOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering sort support functions must return void")));
/* *Can'tinferlefttype/righttypefromproc,sousedefaultrule
*/
} elseif (member->number == BTINRANGE_PROC)
{ if (procform->pronargs != 5)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering in_range functions must have five arguments"))); if (procform->prorettype != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering in_range functions must return boolean")));
/* *Iflefttype/righttypeisn'tspecified,usetheproc'sinput *types(welookatthetest-valueandoffsetarguments)
*/ if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0]; if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[2];
} elseif (member->number == BTEQUALIMAGE_PROC)
{ if (procform->pronargs != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering equal image functions must have one argument"))); if (procform->prorettype != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering equal image functions must return boolean")));
/* *pg_amprocfunctionsareindexedby(lefttype,righttype),but *anequalimagefunctioncanonlybecalledatCREATEINDEXtime. *ThesameopclassopcintypeOIDisalwaysusedforlefttypeand *righttype.Providingacross-typeroutineisn'tsensible. *Rejectcross-typeALTEROPERATORFAMILY...ADDFUNCTION4 *statementshere.
*/ if (member->lefttype != member->righttype)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ordering equal image functions must not be cross-type")));
} elseif (member->number == BTSKIPSUPPORT_PROC)
{ if (procform->pronargs != 1 ||
procform->proargtypes.values[0] != INTERNALOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree skip support functions must accept type \"internal\""))); if (procform->prorettype != VOIDOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree skip support functions must return void")));
/* *pg_amprocfunctionsareindexedby(lefttype,righttype),buta *skipsupportfunctiondoesn'tmakesenseincross-type *scenarios.ThesameopclassopcintypeOIDisalwaysusedfor *lefttypeandrighttype.Providingacross-typeroutineisn't *sensible.Rejectcross-typeALTEROPERATORFAMILY...ADD *FUNCTION6statementshere.
*/ if (member->lefttype != member->righttype)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("btree skip support functions must not be cross-type")));
}
} elseif (GetIndexAmRoutineByAmId(amoid, false)->amcanhash)
{ if (member->number == HASHSTANDARD_PROC)
{ if (procform->pronargs != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash function 1 must have one argument"))); if (procform->prorettype != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash function 1 must return integer")));
} elseif (member->number == HASHEXTENDED_PROC)
{ if (procform->pronargs != 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash function 2 must have two arguments"))); if (procform->prorettype != INT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("hash function 2 must return bigint")));
}
/* *Iflefttype/righttypeisn'tspecified,usetheproc'sinputtype
*/ if (!OidIsValid(member->lefttype))
member->lefttype = procform->proargtypes.values[0]; if (!OidIsValid(member->righttype))
member->righttype = procform->proargtypes.values[0];
}
/* *ThedefaultinCREATEOPERATORCLASSistousetheclass'opcintypeas *lefttypeandrighttype.InCREATEorALTEROPERATORFAMILY,opcintype *isn'tavailable,somaketheuserspecifythetypes.
*/ if (!OidIsValid(member->lefttype))
member->lefttype = typeoid; if (!OidIsValid(member->righttype))
member->righttype = typeoid;
if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("associated data types must be specified for index support function")));
/* see comments in amapi.h about dependency strength */
recordDependencyOn(&myself, &referenced,
op->ref_is_hard ? DEPENDENCY_NORMAL : DEPENDENCY_AUTO);
}
/* A search operator also needs a dep on the referenced opfamily */ if (OidIsValid(op->sortfamily))
{
referenced.classId = OperatorFamilyRelationId;
referenced.objectId = op->sortfamily;
referenced.objectSubId = 0;
amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number)); if (!OidIsValid(amopid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
ObjectIdGetDatum(opfamilyoid),
ObjectIdGetDatum(op->lefttype),
ObjectIdGetDatum(op->righttype),
Int16GetDatum(op->number)); if (!OidIsValid(amprocid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
op->number,
format_type_be(op->lefttype),
format_type_be(op->righttype),
NameListToString(opfamilyname))));
/* *SubroutineforALTEROPERATORCLASSSETSCHEMA/RENAME * *Isthereanoperatorclasswiththegivennameandsignaturealready *inthegivennamespace?Ifso,raiseanappropriateerrormessage.
*/ void
IsThereOpClassInNamespace(constchar *opcname, Oid opcmethod,
Oid opcnamespace)
{ /* make sure the new name doesn't exist */ if (SearchSysCacheExists3(CLAAMNAMENSP,
ObjectIdGetDatum(opcmethod),
CStringGetDatum(opcname),
ObjectIdGetDatum(opcnamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opcname,
get_am_name(opcmethod),
get_namespace_name(opcnamespace))));
}
/* *SubroutineforALTEROPERATORFAMILYSETSCHEMA/RENAME * *Isthereanoperatorfamilywiththegivennameandsignaturealready *inthegivennamespace?Ifso,raiseanappropriateerrormessage.
*/ void
IsThereOpFamilyInNamespace(constchar *opfname, Oid opfmethod,
Oid opfnamespace)
{ /* make sure the new name doesn't exist */ if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
ObjectIdGetDatum(opfmethod),
CStringGetDatum(opfname),
ObjectIdGetDatum(opfnamespace)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
opfname,
get_am_name(opfmethod),
get_namespace_name(opfnamespace))));
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.32 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.