]> granicus.if.org Git - postgresql/blob - src/backend/commands/operatorcmds.c
Replace heapam.h includes with {table, relation}.h where applicable.
[postgresql] / src / backend / commands / operatorcmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * operatorcmds.c
4  *
5  *        Routines for operator manipulation commands
6  *
7  * Portions Copyright (c) 1996-2019, 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 "FooDefine" routines (in src/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  *              Most of the parse-tree manipulation routines are defined in
31  *              commands/manip.c.
32  *
33  *-------------------------------------------------------------------------
34  */
35 #include "postgres.h"
36
37 #include "access/htup_details.h"
38 #include "access/table.h"
39 #include "catalog/dependency.h"
40 #include "catalog/indexing.h"
41 #include "catalog/objectaccess.h"
42 #include "catalog/pg_operator.h"
43 #include "catalog/pg_type.h"
44 #include "commands/alter.h"
45 #include "commands/defrem.h"
46 #include "miscadmin.h"
47 #include "parser/parse_func.h"
48 #include "parser/parse_oper.h"
49 #include "parser/parse_type.h"
50 #include "utils/builtins.h"
51 #include "utils/lsyscache.h"
52 #include "utils/rel.h"
53 #include "utils/syscache.h"
54
55 static Oid      ValidateRestrictionEstimator(List *restrictionName);
56 static Oid      ValidateJoinEstimator(List *joinName);
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  */
66 ObjectAddress
67 DefineOperator(List *names, List *parameters)
68 {
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;
90
91         /* Convert list of names to a name and namespace */
92         oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
93
94         /* Check we have creation rights in target namespace */
95         aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
96         if (aclresult != ACLCHECK_OK)
97                 aclcheck_error(aclresult, OBJECT_SCHEMA,
98                                            get_namespace_name(oprNamespace));
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                 {
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")));
114                 }
115                 else if (strcmp(defel->defname, "rightarg") == 0)
116                 {
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")));
122                 }
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
150                 {
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)));
156                 }
157         }
158
159         /*
160          * make sure we have our required definitions
161          */
162         if (functionName == NIL)
163                 ereport(ERROR,
164                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
165                                  errmsg("operator function must be specified")));
166
167         /* Transform type names to type OIDs */
168         if (typeName1)
169                 typeId1 = typenameTypeId(NULL, typeName1);
170         if (typeName2)
171                 typeId2 = typenameTypeId(NULL, typeName2);
172
173         if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
174                 ereport(ERROR,
175                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
176                                  errmsg("at least one of leftarg or rightarg must be specified")));
177
178         if (typeName1)
179         {
180                 aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
181                 if (aclresult != ACLCHECK_OK)
182                         aclcheck_error_type(aclresult, typeId1);
183         }
184
185         if (typeName2)
186         {
187                 aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
188                 if (aclresult != ACLCHECK_OK)
189                         aclcheck_error_type(aclresult, typeId2);
190         }
191
192         /*
193          * Look up the operator's underlying function.
194          */
195         if (!OidIsValid(typeId1))
196         {
197                 typeId[0] = typeId2;
198                 nargs = 1;
199         }
200         else if (!OidIsValid(typeId2))
201         {
202                 typeId[0] = typeId1;
203                 nargs = 1;
204         }
205         else
206         {
207                 typeId[0] = typeId1;
208                 typeId[1] = typeId2;
209                 nargs = 2;
210         }
211         functionOid = LookupFuncName(functionName, nargs, typeId, false);
212
213         /*
214          * We require EXECUTE rights for the function.  This isn't strictly
215          * necessary, since EXECUTE will be checked at any attempted use of the
216          * operator, but it seems like a good idea anyway.
217          */
218         aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
219         if (aclresult != ACLCHECK_OK)
220                 aclcheck_error(aclresult, OBJECT_FUNCTION,
221                                            NameListToString(functionName));
222
223         rettype = get_func_rettype(functionOid);
224         aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
225         if (aclresult != ACLCHECK_OK)
226                 aclcheck_error_type(aclresult, rettype);
227
228         /*
229          * Look up restriction and join estimators if specified
230          */
231         if (restrictionName)
232                 restrictionOid = ValidateRestrictionEstimator(restrictionName);
233         else
234                 restrictionOid = InvalidOid;
235         if (joinName)
236                 joinOid = ValidateJoinEstimator(joinName);
237         else
238                 joinOid = InvalidOid;
239
240         /*
241          * now have OperatorCreate do all the work..
242          */
243         return
244                 OperatorCreate(oprName, /* operator name */
245                                            oprNamespace,        /* namespace */
246                                            typeId1, /* left type id */
247                                            typeId2, /* right type id */
248                                            functionOid, /* function for operator */
249                                            commutatorName,      /* optional commutator operator name */
250                                            negatorName, /* optional negator operator name */
251                                            restrictionOid,      /* optional restrict. sel. function */
252                                            joinOid, /* optional join sel. function name */
253                                            canMerge,    /* operator merges */
254                                            canHash);    /* operator hashes */
255 }
256
257 /*
258  * Look up a restriction estimator function ny name, and verify that it has
259  * the correct signature and we have the permissions to attach it to an
260  * operator.
261  */
262 static Oid
263 ValidateRestrictionEstimator(List *restrictionName)
264 {
265         Oid                     typeId[4];
266         Oid                     restrictionOid;
267         AclResult       aclresult;
268
269         typeId[0] = INTERNALOID;        /* PlannerInfo */
270         typeId[1] = OIDOID;                     /* operator OID */
271         typeId[2] = INTERNALOID;        /* args list */
272         typeId[3] = INT4OID;            /* varRelid */
273
274         restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
275
276         /* estimators must return float8 */
277         if (get_func_rettype(restrictionOid) != FLOAT8OID)
278                 ereport(ERROR,
279                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
280                                  errmsg("restriction estimator function %s must return type %s",
281                                                 NameListToString(restrictionName), "float8")));
282
283         /* Require EXECUTE rights for the estimator */
284         aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
285         if (aclresult != ACLCHECK_OK)
286                 aclcheck_error(aclresult, OBJECT_FUNCTION,
287                                            NameListToString(restrictionName));
288
289         return restrictionOid;
290 }
291
292 /*
293  * Look up a join estimator function ny name, and verify that it has the
294  * correct signature and we have the permissions to attach it to an
295  * operator.
296  */
297 static Oid
298 ValidateJoinEstimator(List *joinName)
299 {
300         Oid                     typeId[5];
301         Oid                     joinOid;
302         AclResult       aclresult;
303
304         typeId[0] = INTERNALOID;        /* PlannerInfo */
305         typeId[1] = OIDOID;                     /* operator OID */
306         typeId[2] = INTERNALOID;        /* args list */
307         typeId[3] = INT2OID;            /* jointype */
308         typeId[4] = INTERNALOID;        /* SpecialJoinInfo */
309
310         /*
311          * As of Postgres 8.4, the preferred signature for join estimators has 5
312          * arguments, but we still allow the old 4-argument form. Try the
313          * preferred form first.
314          */
315         joinOid = LookupFuncName(joinName, 5, typeId, true);
316         if (!OidIsValid(joinOid))
317                 joinOid = LookupFuncName(joinName, 4, typeId, true);
318         /* If not found, reference the 5-argument signature in error msg */
319         if (!OidIsValid(joinOid))
320                 joinOid = LookupFuncName(joinName, 5, typeId, false);
321
322         /* estimators must return float8 */
323         if (get_func_rettype(joinOid) != FLOAT8OID)
324                 ereport(ERROR,
325                                 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
326                                  errmsg("join estimator function %s must return type %s",
327                                                 NameListToString(joinName), "float8")));
328
329         /* Require EXECUTE rights for the estimator */
330         aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
331         if (aclresult != ACLCHECK_OK)
332                 aclcheck_error(aclresult, OBJECT_FUNCTION,
333                                            NameListToString(joinName));
334
335         return joinOid;
336 }
337
338 /*
339  * Guts of operator deletion.
340  */
341 void
342 RemoveOperatorById(Oid operOid)
343 {
344         Relation        relation;
345         HeapTuple       tup;
346         Form_pg_operator op;
347
348         relation = heap_open(OperatorRelationId, RowExclusiveLock);
349
350         tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
351         if (!HeapTupleIsValid(tup)) /* should not happen */
352                 elog(ERROR, "cache lookup failed for operator %u", operOid);
353         op = (Form_pg_operator) GETSTRUCT(tup);
354
355         /*
356          * Reset links from commutator and negator, if any.  In case of a
357          * self-commutator or self-negator, this means we have to re-fetch the
358          * updated tuple.  (We could optimize away updates on the tuple we're
359          * about to drop, but it doesn't seem worth convoluting the logic for.)
360          */
361         if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
362         {
363                 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
364                 if (operOid == op->oprcom || operOid == op->oprnegate)
365                 {
366                         ReleaseSysCache(tup);
367                         tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
368                         if (!HeapTupleIsValid(tup)) /* should not happen */
369                                 elog(ERROR, "cache lookup failed for operator %u", operOid);
370                 }
371         }
372
373         CatalogTupleDelete(relation, &tup->t_self);
374
375         ReleaseSysCache(tup);
376
377         heap_close(relation, RowExclusiveLock);
378 }
379
380 /*
381  * AlterOperator
382  *              routine implementing ALTER OPERATOR <operator> SET (option = ...).
383  *
384  * Currently, only RESTRICT and JOIN estimator functions can be changed.
385  */
386 ObjectAddress
387 AlterOperator(AlterOperatorStmt *stmt)
388 {
389         ObjectAddress address;
390         Oid                     oprId;
391         Relation        catalog;
392         HeapTuple       tup;
393         Form_pg_operator oprForm;
394         int                     i;
395         ListCell   *pl;
396         Datum           values[Natts_pg_operator];
397         bool            nulls[Natts_pg_operator];
398         bool            replaces[Natts_pg_operator];
399         List       *restrictionName = NIL;      /* optional restrict. sel. function */
400         bool            updateRestriction = false;
401         Oid                     restrictionOid;
402         List       *joinName = NIL; /* optional join sel. function */
403         bool            updateJoin = false;
404         Oid                     joinOid;
405
406         /* Look up the operator */
407         oprId = LookupOperWithArgs(stmt->opername, false);
408         catalog = heap_open(OperatorRelationId, RowExclusiveLock);
409         tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
410         if (tup == NULL)
411                 elog(ERROR, "cache lookup failed for operator %u", oprId);
412         oprForm = (Form_pg_operator) GETSTRUCT(tup);
413
414         /* Process options */
415         foreach(pl, stmt->options)
416         {
417                 DefElem    *defel = (DefElem *) lfirst(pl);
418                 List       *param;
419
420                 if (defel->arg == NULL)
421                         param = NIL;            /* NONE, removes the function */
422                 else
423                         param = defGetQualifiedName(defel);
424
425                 if (strcmp(defel->defname, "restrict") == 0)
426                 {
427                         restrictionName = param;
428                         updateRestriction = true;
429                 }
430                 else if (strcmp(defel->defname, "join") == 0)
431                 {
432                         joinName = param;
433                         updateJoin = true;
434                 }
435
436                 /*
437                  * The rest of the options that CREATE accepts cannot be changed.
438                  * Check for them so that we can give a meaningful error message.
439                  */
440                 else if (strcmp(defel->defname, "leftarg") == 0 ||
441                                  strcmp(defel->defname, "rightarg") == 0 ||
442                                  strcmp(defel->defname, "function") == 0 ||
443                                  strcmp(defel->defname, "procedure") == 0 ||
444                                  strcmp(defel->defname, "commutator") == 0 ||
445                                  strcmp(defel->defname, "negator") == 0 ||
446                                  strcmp(defel->defname, "hashes") == 0 ||
447                                  strcmp(defel->defname, "merges") == 0)
448                 {
449                         ereport(ERROR,
450                                         (errcode(ERRCODE_SYNTAX_ERROR),
451                                          errmsg("operator attribute \"%s\" cannot be changed",
452                                                         defel->defname)));
453                 }
454                 else
455                         ereport(ERROR,
456                                         (errcode(ERRCODE_SYNTAX_ERROR),
457                                          errmsg("operator attribute \"%s\" not recognized",
458                                                         defel->defname)));
459         }
460
461         /* Check permissions. Must be owner. */
462         if (!pg_oper_ownercheck(oprId, GetUserId()))
463                 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
464                                            NameStr(oprForm->oprname));
465
466         /*
467          * Look up restriction and join estimators if specified
468          */
469         if (restrictionName)
470                 restrictionOid = ValidateRestrictionEstimator(restrictionName);
471         else
472                 restrictionOid = InvalidOid;
473         if (joinName)
474                 joinOid = ValidateJoinEstimator(joinName);
475         else
476                 joinOid = InvalidOid;
477
478         /* Perform additional checks, like OperatorCreate does */
479         if (!(OidIsValid(oprForm->oprleft) && OidIsValid(oprForm->oprright)))
480         {
481                 /* If it's not a binary op, these things mustn't be set: */
482                 if (OidIsValid(joinOid))
483                         ereport(ERROR,
484                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
485                                          errmsg("only binary operators can have join selectivity")));
486         }
487
488         if (oprForm->oprresult != BOOLOID)
489         {
490                 if (OidIsValid(restrictionOid))
491                         ereport(ERROR,
492                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
493                                          errmsg("only boolean operators can have restriction selectivity")));
494                 if (OidIsValid(joinOid))
495                         ereport(ERROR,
496                                         (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
497                                          errmsg("only boolean operators can have join selectivity")));
498         }
499
500         /* Update the tuple */
501         for (i = 0; i < Natts_pg_operator; ++i)
502         {
503                 values[i] = (Datum) 0;
504                 replaces[i] = false;
505                 nulls[i] = false;
506         }
507         if (updateRestriction)
508         {
509                 replaces[Anum_pg_operator_oprrest - 1] = true;
510                 values[Anum_pg_operator_oprrest - 1] = restrictionOid;
511         }
512         if (updateJoin)
513         {
514                 replaces[Anum_pg_operator_oprjoin - 1] = true;
515                 values[Anum_pg_operator_oprjoin - 1] = joinOid;
516         }
517
518         tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
519                                                         values, nulls, replaces);
520
521         CatalogTupleUpdate(catalog, &tup->t_self, tup);
522
523         address = makeOperatorDependencies(tup, true);
524
525         InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
526
527         heap_close(catalog, NoLock);
528
529         return address;
530 }