]> granicus.if.org Git - postgresql/blob - src/backend/commands/operatorcmds.c
b4a1aac3a14f5a6292b0cbc6d0da574affa35b4b
[postgresql] / src / backend / commands / operatorcmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * operatorcmds.c
4  *
5  *        Routines for operator manipulation commands
6  *
7  * Portions Copyright (c) 1996-2015, 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 procedures
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/heapam.h"
38 #include "access/htup_details.h"
39 #include "catalog/dependency.h"
40 #include "catalog/indexing.h"
41 #include "catalog/pg_operator.h"
42 #include "catalog/pg_type.h"
43 #include "commands/alter.h"
44 #include "commands/defrem.h"
45 #include "miscadmin.h"
46 #include "parser/parse_func.h"
47 #include "parser/parse_oper.h"
48 #include "parser/parse_type.h"
49 #include "utils/builtins.h"
50 #include "utils/lsyscache.h"
51 #include "utils/rel.h"
52 #include "utils/syscache.h"
53
54 /*
55  * DefineOperator
56  *              this function extracts all the information from the
57  *              parameter list generated by the parser and then has
58  *              OperatorCreate() do all the actual work.
59  *
60  * 'parameters' is a list of DefElem
61  */
62 ObjectAddress
63 DefineOperator(List *names, List *parameters)
64 {
65         char       *oprName;
66         Oid                     oprNamespace;
67         AclResult       aclresult;
68         bool            canMerge = false;               /* operator merges */
69         bool            canHash = false;        /* operator hashes */
70         List       *functionName = NIL;         /* function for operator */
71         TypeName   *typeName1 = NULL;           /* first type name */
72         TypeName   *typeName2 = NULL;           /* second type name */
73         Oid                     typeId1 = InvalidOid;   /* types converted to OID */
74         Oid                     typeId2 = InvalidOid;
75         Oid                     rettype;
76         List       *commutatorName = NIL;       /* optional commutator operator name */
77         List       *negatorName = NIL;          /* optional negator operator name */
78         List       *restrictionName = NIL;      /* optional restrict. sel. procedure */
79         List       *joinName = NIL; /* optional join sel. procedure */
80         Oid                     functionOid;    /* functions converted to OID */
81         Oid                     restrictionOid;
82         Oid                     joinOid;
83         Oid                     typeId[5];              /* only need up to 5 args here */
84         int                     nargs;
85         ListCell   *pl;
86
87         /* Convert list of names to a name and namespace */
88         oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
89
90         /* Check we have creation rights in target namespace */
91         aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
92         if (aclresult != ACLCHECK_OK)
93                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
94                                            get_namespace_name(oprNamespace));
95
96         /*
97          * loop over the definition list and extract the information we need.
98          */
99         foreach(pl, parameters)
100         {
101                 DefElem    *defel = (DefElem *) lfirst(pl);
102
103                 if (pg_strcasecmp(defel->defname, "leftarg") == 0)
104                 {
105                         typeName1 = defGetTypeName(defel);
106                         if (typeName1->setof)
107                                 ereport(ERROR,
108                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
109                                         errmsg("SETOF type not allowed for operator argument")));
110                 }
111                 else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
112                 {
113                         typeName2 = defGetTypeName(defel);
114                         if (typeName2->setof)
115                                 ereport(ERROR,
116                                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
117                                         errmsg("SETOF type not allowed for operator argument")));
118                 }
119                 else if (pg_strcasecmp(defel->defname, "procedure") == 0)
120                         functionName = defGetQualifiedName(defel);
121                 else if (pg_strcasecmp(defel->defname, "commutator") == 0)
122                         commutatorName = defGetQualifiedName(defel);
123                 else if (pg_strcasecmp(defel->defname, "negator") == 0)
124                         negatorName = defGetQualifiedName(defel);
125                 else if (pg_strcasecmp(defel->defname, "restrict") == 0)
126                         restrictionName = defGetQualifiedName(defel);
127                 else if (pg_strcasecmp(defel->defname, "join") == 0)
128                         joinName = defGetQualifiedName(defel);
129                 else if (pg_strcasecmp(defel->defname, "hashes") == 0)
130                         canHash = defGetBoolean(defel);
131                 else if (pg_strcasecmp(defel->defname, "merges") == 0)
132                         canMerge = defGetBoolean(defel);
133                 /* These obsolete options are taken as meaning canMerge */
134                 else if (pg_strcasecmp(defel->defname, "sort1") == 0)
135                         canMerge = true;
136                 else if (pg_strcasecmp(defel->defname, "sort2") == 0)
137                         canMerge = true;
138                 else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
139                         canMerge = true;
140                 else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
141                         canMerge = true;
142                 else
143                         ereport(WARNING,
144                                         (errcode(ERRCODE_SYNTAX_ERROR),
145                                          errmsg("operator attribute \"%s\" not recognized",
146                                                         defel->defname)));
147         }
148
149         /*
150          * make sure we have our required definitions
151          */
152         if (functionName == NIL)
153                 ereport(ERROR,
154                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
155                                  errmsg("operator procedure must be specified")));
156
157         /* Transform type names to type OIDs */
158         if (typeName1)
159                 typeId1 = typenameTypeId(NULL, typeName1);
160         if (typeName2)
161                 typeId2 = typenameTypeId(NULL, typeName2);
162
163         if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
164                 ereport(ERROR,
165                                 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
166                    errmsg("at least one of leftarg or rightarg must be specified")));
167
168         if (typeName1)
169         {
170                 aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
171                 if (aclresult != ACLCHECK_OK)
172                         aclcheck_error_type(aclresult, typeId1);
173         }
174
175         if (typeName2)
176         {
177                 aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
178                 if (aclresult != ACLCHECK_OK)
179                         aclcheck_error_type(aclresult, typeId2);
180         }
181
182         /*
183          * Look up the operator's underlying function.
184          */
185         if (!OidIsValid(typeId1))
186         {
187                 typeId[0] = typeId2;
188                 nargs = 1;
189         }
190         else if (!OidIsValid(typeId2))
191         {
192                 typeId[0] = typeId1;
193                 nargs = 1;
194         }
195         else
196         {
197                 typeId[0] = typeId1;
198                 typeId[1] = typeId2;
199                 nargs = 2;
200         }
201         functionOid = LookupFuncName(functionName, nargs, typeId, false);
202
203         /*
204          * We require EXECUTE rights for the function.  This isn't strictly
205          * necessary, since EXECUTE will be checked at any attempted use of the
206          * operator, but it seems like a good idea anyway.
207          */
208         aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
209         if (aclresult != ACLCHECK_OK)
210                 aclcheck_error(aclresult, ACL_KIND_PROC,
211                                            NameListToString(functionName));
212
213         rettype = get_func_rettype(functionOid);
214         aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
215         if (aclresult != ACLCHECK_OK)
216                 aclcheck_error_type(aclresult, rettype);
217
218         /*
219          * Look up restriction estimator if specified
220          */
221         if (restrictionName)
222         {
223                 typeId[0] = INTERNALOID;        /* PlannerInfo */
224                 typeId[1] = OIDOID;             /* operator OID */
225                 typeId[2] = INTERNALOID;        /* args list */
226                 typeId[3] = INT4OID;    /* varRelid */
227
228                 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
229
230                 /* estimators must return float8 */
231                 if (get_func_rettype(restrictionOid) != FLOAT8OID)
232                         ereport(ERROR,
233                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234                                          errmsg("restriction estimator function %s must return type \"float8\"",
235                                                         NameListToString(restrictionName))));
236
237                 /* Require EXECUTE rights for the estimator */
238                 aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
239                 if (aclresult != ACLCHECK_OK)
240                         aclcheck_error(aclresult, ACL_KIND_PROC,
241                                                    NameListToString(restrictionName));
242         }
243         else
244                 restrictionOid = InvalidOid;
245
246         /*
247          * Look up join estimator if specified
248          */
249         if (joinName)
250         {
251                 typeId[0] = INTERNALOID;        /* PlannerInfo */
252                 typeId[1] = OIDOID;             /* operator OID */
253                 typeId[2] = INTERNALOID;        /* args list */
254                 typeId[3] = INT2OID;    /* jointype */
255                 typeId[4] = INTERNALOID;        /* SpecialJoinInfo */
256
257                 /*
258                  * As of Postgres 8.4, the preferred signature for join estimators has
259                  * 5 arguments, but we still allow the old 4-argument form. Try the
260                  * preferred form first.
261                  */
262                 joinOid = LookupFuncName(joinName, 5, typeId, true);
263                 if (!OidIsValid(joinOid))
264                         joinOid = LookupFuncName(joinName, 4, typeId, true);
265                 /* If not found, reference the 5-argument signature in error msg */
266                 if (!OidIsValid(joinOid))
267                         joinOid = LookupFuncName(joinName, 5, typeId, false);
268
269                 /* estimators must return float8 */
270                 if (get_func_rettype(joinOid) != FLOAT8OID)
271                         ereport(ERROR,
272                                         (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273                          errmsg("join estimator function %s must return type \"float8\"",
274                                         NameListToString(joinName))));
275
276                 /* Require EXECUTE rights for the estimator */
277                 aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
278                 if (aclresult != ACLCHECK_OK)
279                         aclcheck_error(aclresult, ACL_KIND_PROC,
280                                                    NameListToString(joinName));
281         }
282         else
283                 joinOid = InvalidOid;
284
285         /*
286          * now have OperatorCreate do all the work..
287          */
288         return
289                 OperatorCreate(oprName, /* operator name */
290                                            oprNamespace,        /* namespace */
291                                            typeId1, /* left type id */
292                                            typeId2, /* right type id */
293                                            functionOid,         /* function for operator */
294                                            commutatorName,      /* optional commutator operator name */
295                                            negatorName,         /* optional negator operator name */
296                                            restrictionOid,      /* optional restrict. sel. procedure */
297                                            joinOid, /* optional join sel. procedure name */
298                                            canMerge,    /* operator merges */
299                                            canHash);    /* operator hashes */
300 }
301
302 /*
303  * Guts of operator deletion.
304  */
305 void
306 RemoveOperatorById(Oid operOid)
307 {
308         Relation        relation;
309         HeapTuple       tup;
310
311         relation = heap_open(OperatorRelationId, RowExclusiveLock);
312
313         tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
314         if (!HeapTupleIsValid(tup)) /* should not happen */
315                 elog(ERROR, "cache lookup failed for operator %u", operOid);
316
317         simple_heap_delete(relation, &tup->t_self);
318
319         ReleaseSysCache(tup);
320
321         heap_close(relation, RowExclusiveLock);
322 }