Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / backend / commands / operatorcmds.c
blob673648f1fc6f5d49d2654b9dc45740d0e6812dcc
1 /*-------------------------------------------------------------------------
3 * operatorcmds.c
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
11 * IDENTIFICATION
12 * src/backend/commands/operatorcmds.c
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.
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
30 *-------------------------------------------------------------------------
32 #include "postgres.h"
34 #include "access/htup_details.h"
35 #include "access/table.h"
36 #include "catalog/indexing.h"
37 #include "catalog/objectaccess.h"
38 #include "catalog/pg_namespace.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"
52 static Oid ValidateRestrictionEstimator(List *restrictionName);
53 static Oid ValidateJoinEstimator(List *joinName);
54 static Oid ValidateOperatorReference(List *name,
55 Oid leftTypeId,
56 Oid rightTypeId);
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.
64 * 'parameters' is a list of DefElem
66 ObjectAddress
67 DefineOperator(List *names, List *parameters)
69 char *oprName;
70 Oid oprNamespace;
71 AclResult aclresult;
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 */
78 Oid typeId2 = InvalidOid;
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 */
85 Oid restrictionOid;
86 Oid joinOid;
87 Oid typeId[2]; /* to hold left and right arg */
88 int nargs;
89 ListCell *pl;
91 /* Convert list of names to a name and namespace */
92 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
94 /* Check we have creation rights in target namespace */
95 aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
96 if (aclresult != ACLCHECK_OK)
97 aclcheck_error(aclresult, OBJECT_SCHEMA,
98 get_namespace_name(oprNamespace));
101 * loop over the definition list and extract the information we need.
103 foreach(pl, parameters)
105 DefElem *defel = (DefElem *) lfirst(pl);
107 if (strcmp(defel->defname, "leftarg") == 0)
109 typeName1 = defGetTypeName(defel);
110 if (typeName1->setof)
111 ereport(ERROR,
112 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
113 errmsg("SETOF type not allowed for operator argument")));
115 else if (strcmp(defel->defname, "rightarg") == 0)
117 typeName2 = defGetTypeName(defel);
118 if (typeName2->setof)
119 ereport(ERROR,
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)
125 functionName = defGetQualifiedName(defel);
126 else if (strcmp(defel->defname, "procedure") == 0)
127 functionName = defGetQualifiedName(defel);
128 else if (strcmp(defel->defname, "commutator") == 0)
129 commutatorName = defGetQualifiedName(defel);
130 else if (strcmp(defel->defname, "negator") == 0)
131 negatorName = defGetQualifiedName(defel);
132 else if (strcmp(defel->defname, "restrict") == 0)
133 restrictionName = defGetQualifiedName(defel);
134 else if (strcmp(defel->defname, "join") == 0)
135 joinName = defGetQualifiedName(defel);
136 else if (strcmp(defel->defname, "hashes") == 0)
137 canHash = defGetBoolean(defel);
138 else if (strcmp(defel->defname, "merges") == 0)
139 canMerge = defGetBoolean(defel);
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
151 /* WARNING, not ERROR, for historical backwards-compatibility */
152 ereport(WARNING,
153 (errcode(ERRCODE_SYNTAX_ERROR),
154 errmsg("operator attribute \"%s\" not recognized",
155 defel->defname)));
160 * make sure we have our required definitions
162 if (functionName == NIL)
163 ereport(ERROR,
164 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
165 errmsg("operator function must be specified")));
167 /* Transform type names to type OIDs */
168 if (typeName1)
169 typeId1 = typenameTypeId(NULL, typeName1);
170 if (typeName2)
171 typeId2 = typenameTypeId(NULL, typeName2);
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.
180 if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
181 ereport(ERROR,
182 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
183 errmsg("operator argument types must be specified")));
184 if (!OidIsValid(typeId2))
185 ereport(ERROR,
186 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
187 errmsg("operator right argument type must be specified"),
188 errdetail("Postfix operators are not supported.")));
190 if (typeName1)
192 aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
193 if (aclresult != ACLCHECK_OK)
194 aclcheck_error_type(aclresult, typeId1);
197 if (typeName2)
199 aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
200 if (aclresult != ACLCHECK_OK)
201 aclcheck_error_type(aclresult, typeId2);
205 * Look up the operator's underlying function.
207 if (!OidIsValid(typeId1))
209 typeId[0] = typeId2;
210 nargs = 1;
212 else if (!OidIsValid(typeId2))
214 typeId[0] = typeId1;
215 nargs = 1;
217 else
219 typeId[0] = typeId1;
220 typeId[1] = typeId2;
221 nargs = 2;
223 functionOid = LookupFuncName(functionName, nargs, typeId, false);
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.
230 aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
231 if (aclresult != ACLCHECK_OK)
232 aclcheck_error(aclresult, OBJECT_FUNCTION,
233 NameListToString(functionName));
235 rettype = get_func_rettype(functionOid);
236 aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
237 if (aclresult != ACLCHECK_OK)
238 aclcheck_error_type(aclresult, rettype);
241 * Look up restriction and join estimators if specified
243 if (restrictionName)
244 restrictionOid = ValidateRestrictionEstimator(restrictionName);
245 else
246 restrictionOid = InvalidOid;
247 if (joinName)
248 joinOid = ValidateJoinEstimator(joinName);
249 else
250 joinOid = InvalidOid;
253 * now have OperatorCreate do all the work..
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 */
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.
274 static Oid
275 ValidateRestrictionEstimator(List *restrictionName)
277 Oid typeId[4];
278 Oid restrictionOid;
279 AclResult aclresult;
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 */
289 if (get_func_rettype(restrictionOid) != FLOAT8OID)
290 ereport(ERROR,
291 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
292 errmsg("restriction estimator function %s must return type %s",
293 NameListToString(restrictionName), "float8")));
295 /* Require EXECUTE rights for the estimator */
296 aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
297 if (aclresult != ACLCHECK_OK)
298 aclcheck_error(aclresult, OBJECT_FUNCTION,
299 NameListToString(restrictionName));
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
307 * operator.
309 static Oid
310 ValidateJoinEstimator(List *joinName)
312 Oid typeId[5];
313 Oid joinOid;
314 Oid joinOid2;
315 AclResult aclresult;
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.
328 joinOid = LookupFuncName(joinName, 5, typeId, true);
329 joinOid2 = LookupFuncName(joinName, 4, typeId, true);
330 if (OidIsValid(joinOid))
332 if (OidIsValid(joinOid2))
333 ereport(ERROR,
334 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
335 errmsg("join estimator function %s has multiple matches",
336 NameListToString(joinName))));
338 else
340 joinOid = joinOid2;
341 /* If not found, reference the 5-argument signature in error msg */
342 if (!OidIsValid(joinOid))
343 joinOid = LookupFuncName(joinName, 5, typeId, false);
346 /* estimators must return float8 */
347 if (get_func_rettype(joinOid) != FLOAT8OID)
348 ereport(ERROR,
349 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
350 errmsg("join estimator function %s must return type %s",
351 NameListToString(joinName), "float8")));
353 /* Require EXECUTE rights for the estimator */
354 aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
355 if (aclresult != ACLCHECK_OK)
356 aclcheck_error(aclresult, OBJECT_FUNCTION,
357 NameListToString(joinName));
359 return joinOid;
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.
371 static Oid
372 ValidateOperatorReference(List *name,
373 Oid leftTypeId,
374 Oid rightTypeId)
376 Oid oid;
377 bool defined;
379 oid = OperatorLookup(name,
380 leftTypeId,
381 rightTypeId,
382 &defined);
384 /* These message strings are chosen to match parse_oper.c */
385 if (!OidIsValid(oid))
386 ereport(ERROR,
387 (errcode(ERRCODE_UNDEFINED_FUNCTION),
388 errmsg("operator does not exist: %s",
389 op_signature_string(name,
390 leftTypeId,
391 rightTypeId))));
393 if (!defined)
394 ereport(ERROR,
395 (errcode(ERRCODE_UNDEFINED_FUNCTION),
396 errmsg("operator is only a shell: %s",
397 op_signature_string(name,
398 leftTypeId,
399 rightTypeId))));
401 if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
402 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
403 NameListToString(name));
405 return oid;
410 * Guts of operator deletion.
412 void
413 RemoveOperatorById(Oid operOid)
415 Relation relation;
416 HeapTuple tup;
417 Form_pg_operator op;
419 relation = table_open(OperatorRelationId, RowExclusiveLock);
421 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
422 if (!HeapTupleIsValid(tup)) /* should not happen */
423 elog(ERROR, "cache lookup failed for operator %u", operOid);
424 op = (Form_pg_operator) GETSTRUCT(tup);
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.)
432 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
434 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
435 if (operOid == op->oprcom || operOid == op->oprnegate)
437 ReleaseSysCache(tup);
438 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
439 if (!HeapTupleIsValid(tup)) /* should not happen */
440 elog(ERROR, "cache lookup failed for operator %u", operOid);
444 CatalogTupleDelete(relation, &tup->t_self);
446 ReleaseSysCache(tup);
448 table_close(relation, RowExclusiveLock);
452 * AlterOperator
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
459 * than it's worth.)
461 ObjectAddress
462 AlterOperator(AlterOperatorStmt *stmt)
464 ObjectAddress address;
465 Oid oprId;
466 Relation catalog;
467 HeapTuple tup;
468 Form_pg_operator oprForm;
469 int i;
470 ListCell *pl;
471 Datum values[Natts_pg_operator];
472 bool nulls[Natts_pg_operator];
473 bool replaces[Natts_pg_operator];
474 List *restrictionName = NIL; /* optional restrict. sel. function */
475 bool updateRestriction = false;
476 Oid restrictionOid;
477 List *joinName = NIL; /* optional join sel. function */
478 bool updateJoin = false;
479 Oid joinOid;
480 List *commutatorName = NIL; /* optional commutator operator name */
481 Oid commutatorOid;
482 List *negatorName = NIL; /* optional negator operator name */
483 Oid negatorOid;
484 bool canMerge = false;
485 bool updateMerges = false;
486 bool canHash = false;
487 bool updateHashes = false;
489 /* Look up the operator */
490 oprId = LookupOperWithArgs(stmt->opername, false);
491 catalog = table_open(OperatorRelationId, RowExclusiveLock);
492 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
493 if (!HeapTupleIsValid(tup))
494 elog(ERROR, "cache lookup failed for operator %u", oprId);
495 oprForm = (Form_pg_operator) GETSTRUCT(tup);
497 /* Process options */
498 foreach(pl, stmt->options)
500 DefElem *defel = (DefElem *) lfirst(pl);
501 List *param;
503 if (defel->arg == NULL)
504 param = NIL; /* NONE, removes the function */
505 else
506 param = defGetQualifiedName(defel);
508 if (strcmp(defel->defname, "restrict") == 0)
510 restrictionName = param;
511 updateRestriction = true;
513 else if (strcmp(defel->defname, "join") == 0)
515 joinName = param;
516 updateJoin = true;
518 else if (strcmp(defel->defname, "commutator") == 0)
520 commutatorName = defGetQualifiedName(defel);
522 else if (strcmp(defel->defname, "negator") == 0)
524 negatorName = defGetQualifiedName(defel);
526 else if (strcmp(defel->defname, "merges") == 0)
528 canMerge = defGetBoolean(defel);
529 updateMerges = true;
531 else if (strcmp(defel->defname, "hashes") == 0)
533 canHash = defGetBoolean(defel);
534 updateHashes = true;
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)
546 ereport(ERROR,
547 (errcode(ERRCODE_SYNTAX_ERROR),
548 errmsg("operator attribute \"%s\" cannot be changed",
549 defel->defname)));
551 else
552 ereport(ERROR,
553 (errcode(ERRCODE_SYNTAX_ERROR),
554 errmsg("operator attribute \"%s\" not recognized",
555 defel->defname)));
558 /* Check permissions. Must be owner. */
559 if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
560 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
561 NameStr(oprForm->oprname));
564 * Look up OIDs for any parameters specified
566 if (restrictionName)
567 restrictionOid = ValidateRestrictionEstimator(restrictionName);
568 else
569 restrictionOid = InvalidOid;
570 if (joinName)
571 joinOid = ValidateJoinEstimator(joinName);
572 else
573 joinOid = InvalidOid;
575 if (commutatorName)
577 /* commutator has reversed arg types */
578 commutatorOid = ValidateOperatorReference(commutatorName,
579 oprForm->oprright,
580 oprForm->oprleft);
583 * We don't need to do anything extra for a self commutator as in
584 * OperatorCreate, since the operator surely exists already.
587 else
588 commutatorOid = InvalidOid;
590 if (negatorName)
592 negatorOid = ValidateOperatorReference(negatorName,
593 oprForm->oprleft,
594 oprForm->oprright);
596 /* Must reject self-negation */
597 if (negatorOid == oprForm->oid)
598 ereport(ERROR,
599 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
600 errmsg("operator cannot be its own negator")));
602 else
604 negatorOid = InvalidOid;
608 * Check that we're not changing any attributes that might be depended on
609 * by plans, while allowing no-op updates.
611 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
612 commutatorOid != oprForm->oprcom)
613 ereport(ERROR,
614 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
615 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
616 "commutator")));
618 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
619 negatorOid != oprForm->oprnegate)
620 ereport(ERROR,
621 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
622 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
623 "negator")));
625 if (updateMerges && oprForm->oprcanmerge && !canMerge)
626 ereport(ERROR,
627 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
628 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
629 "merges")));
631 if (updateHashes && oprForm->oprcanhash && !canHash)
632 ereport(ERROR,
633 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
634 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
635 "hashes")));
637 /* Perform additional checks, like OperatorCreate does */
638 OperatorValidateParams(oprForm->oprleft,
639 oprForm->oprright,
640 oprForm->oprresult,
641 OidIsValid(commutatorOid),
642 OidIsValid(negatorOid),
643 OidIsValid(restrictionOid),
644 OidIsValid(joinOid),
645 canMerge,
646 canHash);
648 /* Update the tuple */
649 for (i = 0; i < Natts_pg_operator; ++i)
651 values[i] = (Datum) 0;
652 replaces[i] = false;
653 nulls[i] = false;
655 if (updateRestriction)
657 replaces[Anum_pg_operator_oprrest - 1] = true;
658 values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
660 if (updateJoin)
662 replaces[Anum_pg_operator_oprjoin - 1] = true;
663 values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
665 if (OidIsValid(commutatorOid))
667 replaces[Anum_pg_operator_oprcom - 1] = true;
668 values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
670 if (OidIsValid(negatorOid))
672 replaces[Anum_pg_operator_oprnegate - 1] = true;
673 values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
675 if (updateMerges)
677 replaces[Anum_pg_operator_oprcanmerge - 1] = true;
678 values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
680 if (updateHashes)
682 replaces[Anum_pg_operator_oprcanhash - 1] = true;
683 values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
686 tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
687 values, nulls, replaces);
689 CatalogTupleUpdate(catalog, &tup->t_self, tup);
691 address = makeOperatorDependencies(tup, false, true);
693 if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
694 OperatorUpd(oprId, commutatorOid, negatorOid, false);
696 InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
698 table_close(catalog, NoLock);
700 return address;