static Oid ValidateRestrictionEstimator(List *restrictionName); static Oid ValidateJoinEstimator(List *joinName); static Oid ValidateOperatorReference(List *name,
Oid leftTypeId,
Oid rightTypeId);
/* *DefineOperator *thisfunctionextractsalltheinformationfromthe *parameterlistgeneratedbytheparserandthenhas *OperatorCreate()doalltheactualwork. * *'parameters'isalistofDefElem
*/
ObjectAddress
DefineOperator(List *names, List *parameters)
{ char *oprName;
Oid oprNamespace;
AclResult aclresult; bool canMerge = false; /* operator merges */ bool canHash = false; /* operator hashes */
List *functionName = NIL; /* function for operator */ TypeName *typeName1 = NULL; /* first type name */ TypeName *typeName2 = NULL; /* second type name */
Oid typeId1 = InvalidOid; /* types converted to OID */
Oid typeId2 = InvalidOid;
Oid rettype;
List *commutatorName = NIL; /* optional commutator operator name */
List *negatorName = NIL; /* optional negator operator name */
List *restrictionName = NIL; /* optional restrict. sel. function */
List *joinName = NIL; /* optional join sel. function */
Oid functionOid; /* functions converted to OID */
Oid restrictionOid;
Oid joinOid;
Oid typeId[2]; /* to hold left and right arg */ int nargs;
ListCell *pl;
/* Convert list of names to a name and namespace */
oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
/* Check we have creation rights in target namespace */
aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_SCHEMA,
get_namespace_name(oprNamespace));
if (strcmp(defel->defname, "leftarg") == 0)
{
typeName1 = defGetTypeName(defel); if (typeName1->setof)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
} elseif (strcmp(defel->defname, "rightarg") == 0)
{
typeName2 = defGetTypeName(defel); if (typeName2->setof)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("SETOF type not allowed for operator argument")));
} /* "function" and "procedure" are equivalent here */ elseif (strcmp(defel->defname, "function") == 0)
functionName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "procedure") == 0)
functionName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "commutator") == 0)
commutatorName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "negator") == 0)
negatorName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "restrict") == 0)
restrictionName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "join") == 0)
joinName = defGetQualifiedName(defel); elseif (strcmp(defel->defname, "hashes") == 0)
canHash = defGetBoolean(defel); elseif (strcmp(defel->defname, "merges") == 0)
canMerge = defGetBoolean(defel); /* These obsolete options are taken as meaning canMerge */ elseif (strcmp(defel->defname, "sort1") == 0)
canMerge = true; elseif (strcmp(defel->defname, "sort2") == 0)
canMerge = true; elseif (strcmp(defel->defname, "ltcmp") == 0)
canMerge = true; elseif (strcmp(defel->defname, "gtcmp") == 0)
canMerge = true; else
{ /* WARNING, not ERROR, for historical backwards-compatibility */
ereport(WARNING,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("operator attribute \"%s\" not recognized",
defel->defname)));
}
}
/* *makesurewehaveourrequireddefinitions
*/ if (functionName == NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator function must be specified")));
/* Transform type names to type OIDs */ if (typeName1)
typeId1 = typenameTypeId(NULL, typeName1); if (typeName2)
typeId2 = typenameTypeId(NULL, typeName2);
/* *Ifonlytherightargumentismissing,theuserislikelytryingto *createapostfixoperator,sogivethemahintaboutwhythatdoesnot *work.Butifbothargumentsaremissing,donotmentionpostfix *operators,astheusermostlikelysimplyneglectedtomentionthe *arguments.
*/ if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator argument types must be specified"))); if (!OidIsValid(typeId2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator right argument type must be specified"),
errdetail("Postfix operators are not supported.")));
if (typeName1)
{
aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, typeId1);
}
if (typeName2)
{
aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK)
aclcheck_error_type(aclresult, typeId2);
}
/* *nowhaveOperatorCreatedoallthework..
*/ return
OperatorCreate(oprName, /* operator name */
oprNamespace, /* namespace */
typeId1, /* left type id */
typeId2, /* right type id */
functionOid, /* function for operator */
commutatorName, /* optional commutator operator name */
negatorName, /* optional negator operator name */
restrictionOid, /* optional restrict. sel. function */
joinOid, /* optional join sel. function name */
canMerge, /* operator merges */
canHash); /* operator hashes */
}
/* *Lookuparestrictionestimatorfunctionbyname,andverifythatithas *thecorrectsignatureandwehavethepermissionstoattachittoan *operator.
*/ static Oid
ValidateRestrictionEstimator(List *restrictionName)
{
Oid typeId[4];
Oid restrictionOid;
/* estimators must return float8 */ if (get_func_rettype(restrictionOid) != FLOAT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("restriction estimator function %s must return type %s",
NameListToString(restrictionName), "float8")));
/* *Iftheestimatorisnotabuilt-infunction,requiresuperuser *privilegetoinstallit.Thisprotectsagainstusingsomethingthatis *notarestrictionestimatororhashard-wiredassumptionsaboutwhat *datatypesitisworkingwith.(Built-inestimatorsarerequiredto *defendthemselvesadequatelyagainstunexpecteddatatypechoices,but *itseemsimpracticaltoexpectthatofextensions'estimators.) * *Ifitisbuilt-in,onlyrequireEXECUTErights.
*/ if (restrictionOid >= FirstGenbkiObjectId)
{ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to specify a non-built-in restriction estimator function")));
} else
{
AclResult aclresult;
/* *Lookupajoinestimatorfunctionbyname,andverifythatithasthe *correctsignatureandwehavethepermissionstoattachittoan *operator.
*/ static Oid
ValidateJoinEstimator(List *joinName)
{
Oid typeId[5];
Oid joinOid;
Oid joinOid2;
/* *AsofPostgres8.4,thepreferredsignatureforjoinestimatorshas5 *arguments,butwestillallowtheold4-argumentform.Whineabout *ambiguityifbothformsexist.
*/
joinOid = LookupFuncName(joinName, 5, typeId, true);
joinOid2 = LookupFuncName(joinName, 4, typeId, true); if (OidIsValid(joinOid))
{ if (OidIsValid(joinOid2))
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("join estimator function %s has multiple matches",
NameListToString(joinName))));
} else
{
joinOid = joinOid2; /* If not found, reference the 5-argument signature in error msg */ if (!OidIsValid(joinOid))
joinOid = LookupFuncName(joinName, 5, typeId, false);
}
/* estimators must return float8 */ if (get_func_rettype(joinOid) != FLOAT8OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("join estimator function %s must return type %s",
NameListToString(joinName), "float8")));
/* privilege checks are the same as in ValidateRestrictionEstimator */ if (joinOid >= FirstGenbkiObjectId)
{ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to specify a non-built-in join estimator function")));
} else
{
AclResult aclresult;
/* *LookupandreturntheOIDofanoperator, *givenapossibly-qualifiednameandleftandrighttypeIDs. * *Verifiesthattheoperatorisdefined(notashell)andownedby *thecurrentuser,sothatwehavepermissiontoassociateitwith *theoperatorbeingaltered.Rejectingshelloperatorsisapolicy *choicetohelpcatchmistakes,ratherthansomethingessential.
*/ static Oid
ValidateOperatorReference(List *name,
Oid leftTypeId,
Oid rightTypeId)
{
Oid oid; booldefined;
oid = OperatorLookup(name,
leftTypeId,
rightTypeId,
&defined);
/* These message strings are chosen to match parse_oper.c */ if (!OidIsValid(oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s",
op_signature_string(name,
leftTypeId,
rightTypeId))));
if (!defined)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator is only a shell: %s",
op_signature_string(name,
leftTypeId,
rightTypeId))));
if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
NameListToString(name));
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for operator %u", operOid);
op = (Form_pg_operator) GETSTRUCT(tup);
/* *Resetlinksfromcommutatorandnegator,ifany.Incaseofa *self-commutatororself-negator,thismeanswehavetore-fetchthe *updatedtuple.(Wecouldoptimizeawayupdatesonthetuplewe're *abouttodrop,butitdoesn'tseemworthconvolutingthelogicfor.)
*/ if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
{
OperatorUpd(operOid, op->oprcom, op->oprnegate, true); if (operOid == op->oprcom || operOid == op->oprnegate)
{
ReleaseSysCache(tup);
tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid)); if (!HeapTupleIsValid(tup)) /* should not happen */
elog(ERROR, "cache lookup failed for operator %u", operOid);
}
}
CatalogTupleDelete(relation, &tup->t_self);
ReleaseSysCache(tup);
table_close(relation, RowExclusiveLock);
}
/* *AlterOperator *routineimplementingALTEROPERATOR<operator>SET(option=...). * *Currently,onlyRESTRICTandJOINestimatorfunctionscanbechanged. *COMMUTATOR,NEGATOR,MERGES,andHASHESattributescanbesetifthey *havenotbeensetpreviously.(Changingorremovingoneofthese *attributescouldinvalidateexistingplans,whichseemsmoretrouble *thanit'sworth.)
*/
ObjectAddress
AlterOperator(AlterOperatorStmt *stmt)
{
ObjectAddress address;
Oid oprId;
Relation catalog;
HeapTuple tup;
Form_pg_operator oprForm; int i;
ListCell *pl;
Datum values[Natts_pg_operator]; bool nulls[Natts_pg_operator]; bool replaces[Natts_pg_operator];
List *restrictionName = NIL; /* optional restrict. sel. function */ bool updateRestriction = false;
Oid restrictionOid;
List *joinName = NIL; /* optional join sel. function */ bool updateJoin = false;
Oid joinOid;
List *commutatorName = NIL; /* optional commutator operator name */
Oid commutatorOid;
List *negatorName = NIL; /* optional negator operator name */
Oid negatorOid; bool canMerge = false; bool updateMerges = false; bool canHash = false; bool updateHashes = false;
/* Look up the operator */
oprId = LookupOperWithArgs(stmt->opername, false);
catalog = table_open(OperatorRelationId, RowExclusiveLock);
tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId)); if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for operator %u", oprId);
oprForm = (Form_pg_operator) GETSTRUCT(tup);
/* Process options */
foreach(pl, stmt->options)
{
DefElem *defel = (DefElem *) lfirst(pl);
List *param;
if (defel->arg == NULL)
param = NIL; /* NONE, removes the function */ else
param = defGetQualifiedName(defel);
/* Check permissions. Must be owner. */ if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
NameStr(oprForm->oprname));
if (negatorName)
{
negatorOid = ValidateOperatorReference(negatorName,
oprForm->oprleft,
oprForm->oprright);
/* Must reject self-negation */ if (negatorOid == oprForm->oid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator cannot be its own negator")));
} else
{
negatorOid = InvalidOid;
}
/* *Checkthatwe'renotchanginganyattributesthatmightbedependedon *byplans,whileallowingno-opupdates.
*/ if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
commutatorOid != oprForm->oprcom)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator attribute \"%s\" cannot be changed if it has already been set", "commutator")));
if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
negatorOid != oprForm->oprnegate)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator attribute \"%s\" cannot be changed if it has already been set", "negator")));
if (updateMerges && oprForm->oprcanmerge && !canMerge)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator attribute \"%s\" cannot be changed if it has already been set", "merges")));
if (updateHashes && oprForm->oprcanhash && !canHash)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("operator attribute \"%s\" cannot be changed if it has already been set", "hashes")));
/* Perform additional checks, like OperatorCreate does */
OperatorValidateParams(oprForm->oprleft,
oprForm->oprright,
oprForm->oprresult,
OidIsValid(commutatorOid),
OidIsValid(negatorOid),
OidIsValid(restrictionOid),
OidIsValid(joinOid),
canMerge,
canHash);
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.