PostgreSQL Source Code git master
Loading...
Searching...
No Matches
operatorcmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * operatorcmds.c
4 *
5 * Routines for operator manipulation commands
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 *
11 * IDENTIFICATION
12 * src/backend/commands/operatorcmds.c
13 *
14 * DESCRIPTION
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.
20 *
21 * NOTES
22 * These things must be defined and committed in the following order:
23 * "create function":
24 * input/output, recv/send functions
25 * "create type":
26 * type
27 * "create operator":
28 * operators
29 *
30 *-------------------------------------------------------------------------
31 */
32#include "postgres.h"
33
34#include "access/htup_details.h"
35#include "access/table.h"
36#include "catalog/indexing.h"
39#include "catalog/pg_operator.h"
40#include "catalog/pg_proc.h"
41#include "catalog/pg_type.h"
42#include "commands/defrem.h"
43#include "miscadmin.h"
44#include "parser/parse_func.h"
45#include "parser/parse_oper.h"
46#include "parser/parse_type.h"
47#include "utils/acl.h"
48#include "utils/lsyscache.h"
49#include "utils/rel.h"
50#include "utils/syscache.h"
51
57
58/*
59 * DefineOperator
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.
63 *
64 * 'parameters' is a list of DefElem
65 */
67DefineOperator(List *names, List *parameters)
68{
69 char *oprName;
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 */
77 Oid typeId1 = InvalidOid; /* types converted to OID */
79 Oid rettype;
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 */
88 int nargs;
89 ListCell *pl;
90
91 /* Convert list of names to a name and namespace */
93
94 /* Check we have creation rights in target namespace */
99
100 /*
101 * loop over the definition list and extract the information we need.
102 */
103 foreach(pl, parameters)
104 {
105 DefElem *defel = (DefElem *) lfirst(pl);
106
107 if (strcmp(defel->defname, "leftarg") == 0)
108 {
110 if (typeName1->setof)
113 errmsg("SETOF type not allowed for operator argument")));
114 }
115 else if (strcmp(defel->defname, "rightarg") == 0)
116 {
118 if (typeName2->setof)
121 errmsg("SETOF type not allowed for operator argument")));
122 }
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)
142 canMerge = true;
143 else if (strcmp(defel->defname, "sort2") == 0)
144 canMerge = true;
145 else if (strcmp(defel->defname, "ltcmp") == 0)
146 canMerge = true;
147 else if (strcmp(defel->defname, "gtcmp") == 0)
148 canMerge = true;
149 else
150 {
151 /* WARNING, not ERROR, for historical backwards-compatibility */
154 errmsg("operator attribute \"%s\" not recognized",
155 defel->defname)));
156 }
157 }
158
159 /*
160 * make sure we have our required definitions
161 */
162 if (functionName == NIL)
165 errmsg("operator function must be specified")));
166
167 /* Transform type names to type OIDs */
168 if (typeName1)
170 if (typeName2)
172
173 /*
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
178 * arguments.
179 */
183 errmsg("operator argument types must be specified")));
184 if (!OidIsValid(typeId2))
187 errmsg("operator right argument type must be specified"),
188 errdetail("Postfix operators are not supported.")));
189
190 if (typeName1)
191 {
193 if (aclresult != ACLCHECK_OK)
195 }
196
197 if (typeName2)
198 {
200 if (aclresult != ACLCHECK_OK)
202 }
203
204 /*
205 * Look up the operator's underlying function.
206 */
207 if (!OidIsValid(typeId1))
208 {
209 typeId[0] = typeId2;
210 nargs = 1;
211 }
212 else if (!OidIsValid(typeId2))
213 {
214 typeId[0] = typeId1;
215 nargs = 1;
216 }
217 else
218 {
219 typeId[0] = typeId1;
220 typeId[1] = typeId2;
221 nargs = 2;
222 }
223 functionOid = LookupFuncName(functionName, nargs, typeId, false);
224
225 /*
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.
229 */
231 if (aclresult != ACLCHECK_OK)
234
235 rettype = get_func_rettype(functionOid);
237 if (aclresult != ACLCHECK_OK)
239
240 /*
241 * Look up restriction and join estimators if specified
242 */
243 if (restrictionName)
245 else
247 if (joinName)
249 else
251
252 /*
253 * now have OperatorCreate do all the work..
254 */
255 return
256 OperatorCreate(oprName, /* operator name */
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 */
267}
268
269/*
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
272 * operator.
273 */
274static Oid
276{
277 Oid typeId[4];
279
280 typeId[0] = INTERNALOID; /* PlannerInfo */
281 typeId[1] = OIDOID; /* operator OID */
282 typeId[2] = INTERNALOID; /* args list */
283 typeId[3] = INT4OID; /* varRelid */
284
285 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
286
287 /* estimators must return float8 */
291 errmsg("restriction estimator function %s must return type %s",
292 NameListToString(restrictionName), "float8")));
293
294 /*
295 * If the estimator is not a built-in function, require superuser
296 * privilege to install it. This protects against using something that is
297 * not a restriction estimator or has hard-wired assumptions about what
298 * data types it is working with. (Built-in estimators are required to
299 * defend themselves adequately against unexpected data type choices, but
300 * it seems impractical to expect that of extensions' estimators.)
301 *
302 * If it is built-in, only require EXECUTE rights.
303 */
305 {
306 if (!superuser())
309 errmsg("must be superuser to specify a non-built-in restriction estimator function")));
310 }
311 else
312 {
314
317 if (aclresult != ACLCHECK_OK)
320 }
321
322 return restrictionOid;
323}
324
325/*
326 * Look up a join estimator function by name, and verify that it has the
327 * correct signature and we have the permissions to attach it to an
328 * operator.
329 */
330static Oid
332{
333 Oid typeId[5];
334 Oid joinOid;
336
337 typeId[0] = INTERNALOID; /* PlannerInfo */
338 typeId[1] = OIDOID; /* operator OID */
339 typeId[2] = INTERNALOID; /* args list */
340 typeId[3] = INT2OID; /* jointype */
341 typeId[4] = INTERNALOID; /* SpecialJoinInfo */
342
343 /*
344 * As of Postgres 8.4, the preferred signature for join estimators has 5
345 * arguments, but we still allow the old 4-argument form. Whine about
346 * ambiguity if both forms exist.
347 */
348 joinOid = LookupFuncName(joinName, 5, typeId, true);
349 joinOid2 = LookupFuncName(joinName, 4, typeId, true);
350 if (OidIsValid(joinOid))
351 {
352 if (OidIsValid(joinOid2))
355 errmsg("join estimator function %s has multiple matches",
357 }
358 else
359 {
361 /* If not found, reference the 5-argument signature in error msg */
362 if (!OidIsValid(joinOid))
363 joinOid = LookupFuncName(joinName, 5, typeId, false);
364 }
365
366 /* estimators must return float8 */
370 errmsg("join estimator function %s must return type %s",
371 NameListToString(joinName), "float8")));
372
373 /* privilege checks are the same as in ValidateRestrictionEstimator */
375 {
376 if (!superuser())
379 errmsg("must be superuser to specify a non-built-in join estimator function")));
380 }
381 else
382 {
384
387 if (aclresult != ACLCHECK_OK)
390 }
391
392 return joinOid;
393}
394
395/*
396 * Look up and return the OID of an operator,
397 * given a possibly-qualified name and left and right type IDs.
398 *
399 * Verifies that the operator is defined (not a shell) and owned by
400 * the current user, so that we have permission to associate it with
401 * the operator being altered. Rejecting shell operators is a policy
402 * choice to help catch mistakes, rather than something essential.
403 */
404static Oid
408{
409 Oid oid;
410 bool defined;
411
412 oid = OperatorLookup(name,
415 &defined);
416
417 /* These message strings are chosen to match parse_oper.c */
418 if (!OidIsValid(oid))
421 errmsg("operator does not exist: %s",
424 rightTypeId))));
425
426 if (!defined)
429 errmsg("operator is only a shell: %s",
432 rightTypeId))));
433
437
438 return oid;
439}
440
441
442/*
443 * Guts of operator deletion.
444 */
445void
447{
448 Relation relation;
451
453
455 if (!HeapTupleIsValid(tup)) /* should not happen */
456 elog(ERROR, "cache lookup failed for operator %u", operOid);
458
459 /*
460 * Reset links from commutator and negator, if any. In case of a
461 * self-commutator or self-negator, this means we have to re-fetch the
462 * updated tuple. (We could optimize away updates on the tuple we're
463 * about to drop, but it doesn't seem worth convoluting the logic for.)
464 */
465 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
466 {
467 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
468 if (operOid == op->oprcom || operOid == op->oprnegate)
469 {
472 if (!HeapTupleIsValid(tup)) /* should not happen */
473 elog(ERROR, "cache lookup failed for operator %u", operOid);
474 }
475 }
476
477 CatalogTupleDelete(relation, &tup->t_self);
478
480
481 table_close(relation, RowExclusiveLock);
482}
483
484/*
485 * AlterOperator
486 * routine implementing ALTER OPERATOR <operator> SET (option = ...).
487 *
488 * Currently, only RESTRICT and JOIN estimator functions can be changed.
489 * COMMUTATOR, NEGATOR, MERGES, and HASHES attributes can be set if they
490 * have not been set previously. (Changing or removing one of these
491 * attributes could invalidate existing plans, which seems more trouble
492 * than it's worth.)
493 */
496{
497 ObjectAddress address;
498 Oid oprId;
502 int i;
503 ListCell *pl;
505 bool nulls[Natts_pg_operator];
507 List *restrictionName = NIL; /* optional restrict. sel. function */
508 bool updateRestriction = false;
510 List *joinName = NIL; /* optional join sel. function */
511 bool updateJoin = false;
512 Oid joinOid;
513 List *commutatorName = NIL; /* optional commutator operator name */
515 List *negatorName = NIL; /* optional negator operator name */
517 bool canMerge = false;
518 bool updateMerges = false;
519 bool canHash = false;
520 bool updateHashes = false;
521
522 /* Look up the operator */
523 oprId = LookupOperWithArgs(stmt->opername, false);
526 if (!HeapTupleIsValid(tup))
527 elog(ERROR, "cache lookup failed for operator %u", oprId);
529
530 /* Process options */
531 foreach(pl, stmt->options)
532 {
533 DefElem *defel = (DefElem *) lfirst(pl);
534 List *param;
535
536 if (defel->arg == NULL)
537 param = NIL; /* NONE, removes the function */
538 else
539 param = defGetQualifiedName(defel);
540
541 if (strcmp(defel->defname, "restrict") == 0)
542 {
543 restrictionName = param;
544 updateRestriction = true;
545 }
546 else if (strcmp(defel->defname, "join") == 0)
547 {
548 joinName = param;
549 updateJoin = true;
550 }
551 else if (strcmp(defel->defname, "commutator") == 0)
552 {
554 }
555 else if (strcmp(defel->defname, "negator") == 0)
556 {
558 }
559 else if (strcmp(defel->defname, "merges") == 0)
560 {
562 updateMerges = true;
563 }
564 else if (strcmp(defel->defname, "hashes") == 0)
565 {
567 updateHashes = true;
568 }
569
570 /*
571 * The rest of the options that CREATE accepts cannot be changed.
572 * Check for them so that we can give a meaningful error message.
573 */
574 else if (strcmp(defel->defname, "leftarg") == 0 ||
575 strcmp(defel->defname, "rightarg") == 0 ||
576 strcmp(defel->defname, "function") == 0 ||
577 strcmp(defel->defname, "procedure") == 0)
578 {
581 errmsg("operator attribute \"%s\" cannot be changed",
582 defel->defname)));
583 }
584 else
587 errmsg("operator attribute \"%s\" not recognized",
588 defel->defname)));
589 }
590
591 /* Check permissions. Must be owner. */
594 NameStr(oprForm->oprname));
595
596 /*
597 * Look up OIDs for any parameters specified
598 */
599 if (restrictionName)
601 else
603 if (joinName)
605 else
607
608 if (commutatorName)
609 {
610 /* commutator has reversed arg types */
612 oprForm->oprright,
613 oprForm->oprleft);
614
615 /*
616 * We don't need to do anything extra for a self commutator as in
617 * OperatorCreate, since the operator surely exists already.
618 */
619 }
620 else
622
623 if (negatorName)
624 {
626 oprForm->oprleft,
627 oprForm->oprright);
628
629 /* Must reject self-negation */
630 if (negatorOid == oprForm->oid)
633 errmsg("operator cannot be its own negator")));
634 }
635 else
636 {
638 }
639
640 /*
641 * Check that we're not changing any attributes that might be depended on
642 * by plans, while allowing no-op updates.
643 */
644 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
645 commutatorOid != oprForm->oprcom)
648 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
649 "commutator")));
650
651 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
652 negatorOid != oprForm->oprnegate)
655 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
656 "negator")));
657
658 if (updateMerges && oprForm->oprcanmerge && !canMerge)
661 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
662 "merges")));
663
664 if (updateHashes && oprForm->oprcanhash && !canHash)
667 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
668 "hashes")));
669
670 /* Perform additional checks, like OperatorCreate does */
672 oprForm->oprright,
673 oprForm->oprresult,
678 canMerge,
679 canHash);
680
681 /* Update the tuple */
682 for (i = 0; i < Natts_pg_operator; ++i)
683 {
684 values[i] = (Datum) 0;
685 replaces[i] = false;
686 nulls[i] = false;
687 }
689 {
692 }
693 if (updateJoin)
694 {
697 }
699 {
702 }
704 {
707 }
708 if (updateMerges)
709 {
712 }
713 if (updateHashes)
714 {
717 }
718
720 values, nulls, replaces);
721
722 CatalogTupleUpdate(catalog, &tup->t_self, tup);
723
724 address = makeOperatorDependencies(tup, false, true);
725
728
730
732
733 return address;
734}
AclResult
Definition acl.h:182
@ ACLCHECK_OK
Definition acl.h:183
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3854
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4108
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition aclchk.c:2973
static Datum values[MAXATTR]
Definition bootstrap.c:147
#define NameStr(name)
Definition c.h:777
#define OidIsValid(objectId)
Definition c.h:800
TypeName * defGetTypeName(DefElem *def)
Definition define.c:270
bool defGetBoolean(DefElem *def)
Definition define.c:93
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
int errcode(int sqlerrcode)
Definition elog.c:874
int errmsg(const char *fmt,...)
Definition elog.c:1093
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1210
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
int i
Definition isn.c:77
#define NoLock
Definition lockdefs.h:34
#define RowExclusiveLock
Definition lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3518
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1805
Oid GetUserId(void)
Definition miscinit.c:469
char * NameListToString(const List *names)
Definition namespace.c:3666
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3559
#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)
Definition parse_oper.c:608
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition parse_oper.c:135
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
#define ACL_USAGE
Definition parsenodes.h:84
@ OBJECT_SCHEMA
@ OBJECT_OPERATOR
@ OBJECT_FUNCTION
#define ACL_EXECUTE
Definition parsenodes.h:83
#define ACL_CREATE
Definition parsenodes.h:85
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
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)
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
Definition pg_list.h:54
bool superuser(void)
Definition superuser.c:47
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
#define FirstGenbkiObjectId
Definition transam.h:195
const char * name