1/*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/commands/operatorcmds.c
15 * The "DefineFoo" routines take the parse tree and pick out the
16 * appropriate arguments/flags, passing the results to the
17 * corresponding "FooCreate" routines (in src/backend/catalog) that do
18 * the actual catalog-munging. These routines also verify permission
19 * of the user to execute the command.
22 * These things must be defined and committed in the following order:
24 * input/output, recv/send functions
30 *-------------------------------------------------------------------------
60 * this function extracts all the information from the
61 * parameter list generated by the parser and then has
62 * OperatorCreate() do all the actual work.
64 * 'parameters' is a list of DefElem
72 bool canMerge =
false;
/* operator merges */
73 bool canHash =
false;
/* operator hashes */
74 List *functionName =
NIL;
/* function for operator */
75 TypeName *typeName1 = NULL;
/* first type name */
76 TypeName *typeName2 = NULL;
/* second type name */
80 List *commutatorName =
NIL;
/* optional commutator operator name */
81 List *negatorName =
NIL;
/* optional negator operator name */
82 List *restrictionName =
NIL;
/* optional restrict. sel. function */
83 List *joinName =
NIL;
/* optional join sel. function */
84 Oid functionOid;
/* functions converted to OID */
87 Oid typeId[2];
/* to hold left and right arg */
91 /* Convert list of names to a name and namespace */
94 /* Check we have creation rights in target namespace */
101 * loop over the definition list and extract the information we need.
103 foreach(pl, parameters)
107 if (strcmp(defel->
defname,
"leftarg") == 0)
110 if (typeName1->
setof)
112 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
113 errmsg(
"SETOF type not allowed for operator argument")));
115 else if (strcmp(defel->
defname,
"rightarg") == 0)
118 if (typeName2->
setof)
120 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
121 errmsg(
"SETOF type not allowed for operator argument")));
123 /* "function" and "procedure" are equivalent here */
124 else if (strcmp(defel->
defname,
"function") == 0)
126 else if (strcmp(defel->
defname,
"procedure") == 0)
128 else if (strcmp(defel->
defname,
"commutator") == 0)
130 else if (strcmp(defel->
defname,
"negator") == 0)
132 else if (strcmp(defel->
defname,
"restrict") == 0)
134 else if (strcmp(defel->
defname,
"join") == 0)
136 else if (strcmp(defel->
defname,
"hashes") == 0)
138 else if (strcmp(defel->
defname,
"merges") == 0)
140 /* These obsolete options are taken as meaning canMerge */
141 else if (strcmp(defel->
defname,
"sort1") == 0)
143 else if (strcmp(defel->
defname,
"sort2") == 0)
145 else if (strcmp(defel->
defname,
"ltcmp") == 0)
147 else if (strcmp(defel->
defname,
"gtcmp") == 0)
151 /* WARNING, not ERROR, for historical backwards-compatibility */
153 (
errcode(ERRCODE_SYNTAX_ERROR),
154 errmsg(
"operator attribute \"%s\" not recognized",
160 * make sure we have our required definitions
162 if (functionName ==
NIL)
164 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
165 errmsg(
"operator function must be specified")));
167 /* Transform type names to type OIDs */
174 * If only the right argument is missing, the user is likely trying to
175 * create a postfix operator, so give them a hint about why that does not
176 * work. But if both arguments are missing, do not mention postfix
177 * operators, as the user most likely simply neglected to mention the
182 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
183 errmsg(
"operator argument types must be specified")));
186 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
187 errmsg(
"operator right argument type must be specified"),
188 errdetail(
"Postfix operators are not supported.")));
205 * Look up the operator's underlying function.
226 * We require EXECUTE rights for the function. This isn't strictly
227 * necessary, since EXECUTE will be checked at any attempted use of the
228 * operator, but it seems like a good idea anyway.
241 * Look up restriction and join estimators if specified
253 * now have OperatorCreate do all the work..
257 oprNamespace,
/* namespace */
258 typeId1,
/* left type id */
259 typeId2,
/* right type id */
260 functionOid,
/* function for operator */
261 commutatorName,
/* optional commutator operator name */
262 negatorName,
/* optional negator operator name */
263 restrictionOid,
/* optional restrict. sel. function */
264 joinOid,
/* optional join sel. function name */
265 canMerge,
/* operator merges */
266 canHash);
/* operator hashes */
270 * Look up a restriction estimator function by name, and verify that it has
271 * the correct signature and we have the permissions to attach it to an
281 typeId[0] = INTERNALOID;
/* PlannerInfo */
282 typeId[1] = OIDOID;
/* operator OID */
283 typeId[2] = INTERNALOID;
/* args list */
284 typeId[3] = INT4OID;
/* varRelid */
286 restrictionOid =
LookupFuncName(restrictionName, 4, typeId,
false);
288 /* estimators must return float8 */
291 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
292 errmsg(
"restriction estimator function %s must return type %s",
295 /* Require EXECUTE rights for the estimator */
301 return restrictionOid;
305 * Look up a join estimator function by name, and verify that it has the
306 * correct signature and we have the permissions to attach it to an
317 typeId[0] = INTERNALOID;
/* PlannerInfo */
318 typeId[1] = OIDOID;
/* operator OID */
319 typeId[2] = INTERNALOID;
/* args list */
320 typeId[3] = INT2OID;
/* jointype */
321 typeId[4] = INTERNALOID;
/* SpecialJoinInfo */
324 * As of Postgres 8.4, the preferred signature for join estimators has 5
325 * arguments, but we still allow the old 4-argument form. Whine about
326 * ambiguity if both forms exist.
334 (
errcode(ERRCODE_AMBIGUOUS_FUNCTION),
335 errmsg(
"join estimator function %s has multiple matches",
341 /* If not found, reference the 5-argument signature in error msg */
346 /* estimators must return float8 */
349 (
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
350 errmsg(
"join estimator function %s must return type %s",
353 /* Require EXECUTE rights for the estimator */
363 * Look up and return the OID of an operator,
364 * given a possibly-qualified name and left and right type IDs.
366 * Verifies that the operator is defined (not a shell) and owned by
367 * the current user, so that we have permission to associate it with
368 * the operator being altered. Rejecting shell operators is a policy
369 * choice to help catch mistakes, rather than something essential.
384 /* These message strings are chosen to match parse_oper.c */
387 (
errcode(ERRCODE_UNDEFINED_FUNCTION),
388 errmsg(
"operator does not exist: %s",
395 (
errcode(ERRCODE_UNDEFINED_FUNCTION),
396 errmsg(
"operator is only a shell: %s",
410 * Guts of operator deletion.
423 elog(
ERROR,
"cache lookup failed for operator %u", operOid);
427 * Reset links from commutator and negator, if any. In case of a
428 * self-commutator or self-negator, this means we have to re-fetch the
429 * updated tuple. (We could optimize away updates on the tuple we're
430 * about to drop, but it doesn't seem worth convoluting the logic for.)
434 OperatorUpd(operOid, op->oprcom, op->oprnegate,
true);
435 if (operOid == op->oprcom || operOid == op->oprnegate)
440 elog(
ERROR,
"cache lookup failed for operator %u", operOid);
453 * routine implementing ALTER OPERATOR <operator> SET (option = ...).
455 * Currently, only RESTRICT and JOIN estimator functions can be changed.
456 * COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
457 * have not been set previously. (Changing or removing one of these
458 * attributes could invalidate existing plans, which seems more trouble
472 bool nulls[Natts_pg_operator];
473 bool replaces[Natts_pg_operator];
474 List *restrictionName =
NIL;
/* optional restrict. sel. function */
475 bool updateRestriction =
false;
477 List *joinName =
NIL;
/* optional join sel. function */
478 bool updateJoin =
false;
480 List *commutatorName =
NIL;
/* optional commutator operator name */
482 List *negatorName =
NIL;
/* optional negator operator name */
484 bool canMerge =
false;
485 bool updateMerges =
false;
486 bool canHash =
false;
487 bool updateHashes =
false;
489 /* Look up the operator */
494 elog(
ERROR,
"cache lookup failed for operator %u", oprId);
497 /* Process options */
498 foreach(pl,
stmt->options)
503 if (defel->
arg == NULL)
504 param =
NIL;
/* NONE, removes the function */
508 if (strcmp(defel->
defname,
"restrict") == 0)
510 restrictionName = param;
511 updateRestriction =
true;
513 else if (strcmp(defel->
defname,
"join") == 0)
518 else if (strcmp(defel->
defname,
"commutator") == 0)
522 else if (strcmp(defel->
defname,
"negator") == 0)
526 else if (strcmp(defel->
defname,
"merges") == 0)
531 else if (strcmp(defel->
defname,
"hashes") == 0)
538 * The rest of the options that CREATE accepts cannot be changed.
539 * Check for them so that we can give a meaningful error message.
541 else if (strcmp(defel->
defname,
"leftarg") == 0 ||
542 strcmp(defel->
defname,
"rightarg") == 0 ||
543 strcmp(defel->
defname,
"function") == 0 ||
544 strcmp(defel->
defname,
"procedure") == 0)
547 (
errcode(ERRCODE_SYNTAX_ERROR),
548 errmsg(
"operator attribute \"%s\" cannot be changed",
553 (
errcode(ERRCODE_SYNTAX_ERROR),
554 errmsg(
"operator attribute \"%s\" not recognized",
558 /* Check permissions. Must be owner. */
564 * Look up OIDs for any parameters specified
577 /* commutator has reversed arg types */
583 * We don't need to do anything extra for a self commutator as in
584 * OperatorCreate, since the operator surely exists already.
596 /* Must reject self-negation */
597 if (negatorOid == oprForm->oid)
599 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
600 errmsg(
"operator cannot be its own negator")));
608 * Check that we're not changing any attributes that might be depended on
609 * by plans, while allowing no-op updates.
612 commutatorOid != oprForm->oprcom)
614 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
615 errmsg(
"operator attribute \"%s\" cannot be changed if it has already been set",
619 negatorOid != oprForm->oprnegate)
621 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
622 errmsg(
"operator attribute \"%s\" cannot be changed if it has already been set",
625 if (updateMerges && oprForm->oprcanmerge && !canMerge)
627 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
628 errmsg(
"operator attribute \"%s\" cannot be changed if it has already been set",
631 if (updateHashes && oprForm->oprcanhash && !canHash)
633 (
errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
634 errmsg(
"operator attribute \"%s\" cannot be changed if it has already been set",
637 /* Perform additional checks, like OperatorCreate does */
648 /* Update the tuple */
649 for (
i = 0;
i < Natts_pg_operator; ++
i)
655 if (updateRestriction)
657 replaces[Anum_pg_operator_oprrest - 1] =
true;
662 replaces[Anum_pg_operator_oprjoin - 1] =
true;
667 replaces[Anum_pg_operator_oprcom - 1] =
true;
672 replaces[Anum_pg_operator_oprnegate - 1] =
true;
677 replaces[Anum_pg_operator_oprcanmerge - 1] =
true;
682 replaces[Anum_pg_operator_oprcanhash - 1] =
true;
694 OperatorUpd(oprId, commutatorOid, negatorOid,
false);
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
static Datum values[MAXATTR]
#define OidIsValid(objectId)
TypeName * defGetTypeName(DefElem *def)
bool defGetBoolean(DefElem *def)
List * defGetQualifiedName(DefElem *def)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
#define HeapTupleIsValid(tuple)
static void * GETSTRUCT(const HeapTupleData *tuple)
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
char * get_namespace_name(Oid nspid)
Oid get_func_rettype(Oid funcid)
char * NameListToString(const List *names)
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
ObjectAddress AlterOperator(AlterOperatorStmt *stmt)
void RemoveOperatorById(Oid operOid)
static Oid ValidateJoinEstimator(List *joinName)
static Oid ValidateOperatorReference(List *name, Oid leftTypeId, Oid rightTypeId)
ObjectAddress DefineOperator(List *names, List *parameters)
static Oid ValidateRestrictionEstimator(List *restrictionName)
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
const char * op_signature_string(List *op, Oid arg1, Oid arg2)
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
ObjectAddress OperatorCreate(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
FormData_pg_operator * Form_pg_operator
static Datum BoolGetDatum(bool X)
static Datum ObjectIdGetDatum(Oid X)
#define RelationGetDescr(relation)
void ReleaseSysCache(HeapTuple tuple)
HeapTuple SearchSysCache1(int cacheId, Datum key1)
#define SearchSysCacheCopy1(cacheId, key1)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)