1 /*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2015, 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 "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.
22 * These things must be defined and committed in the following order:
24 * input/output, recv/send procedures
30 * Most of the parse-tree manipulation routines are defined in
33 *-------------------------------------------------------------------------
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"
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.
60 * 'parameters' is a list of DefElem
63 DefineOperator(List *names, List *parameters)
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;
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 */
83 Oid typeId[5]; /* only need up to 5 args here */
87 /* Convert list of names to a name and namespace */
88 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
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));
97 * loop over the definition list and extract the information we need.
99 foreach(pl, parameters)
101 DefElem *defel = (DefElem *) lfirst(pl);
103 if (pg_strcasecmp(defel->defname, "leftarg") == 0)
105 typeName1 = defGetTypeName(defel);
106 if (typeName1->setof)
108 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
109 errmsg("SETOF type not allowed for operator argument")));
111 else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
113 typeName2 = defGetTypeName(defel);
114 if (typeName2->setof)
116 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
117 errmsg("SETOF type not allowed for operator argument")));
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)
136 else if (pg_strcasecmp(defel->defname, "sort2") == 0)
138 else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
140 else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
144 (errcode(ERRCODE_SYNTAX_ERROR),
145 errmsg("operator attribute \"%s\" not recognized",
150 * make sure we have our required definitions
152 if (functionName == NIL)
154 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
155 errmsg("operator procedure must be specified")));
157 /* Transform type names to type OIDs */
159 typeId1 = typenameTypeId(NULL, typeName1);
161 typeId2 = typenameTypeId(NULL, typeName2);
163 if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
165 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
166 errmsg("at least one of leftarg or rightarg must be specified")));
170 aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
171 if (aclresult != ACLCHECK_OK)
172 aclcheck_error_type(aclresult, typeId1);
177 aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
178 if (aclresult != ACLCHECK_OK)
179 aclcheck_error_type(aclresult, typeId2);
183 * Look up the operator's underlying function.
185 if (!OidIsValid(typeId1))
190 else if (!OidIsValid(typeId2))
201 functionOid = LookupFuncName(functionName, nargs, typeId, false);
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.
208 aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
209 if (aclresult != ACLCHECK_OK)
210 aclcheck_error(aclresult, ACL_KIND_PROC,
211 NameListToString(functionName));
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);
219 * Look up restriction estimator if specified
223 typeId[0] = INTERNALOID; /* PlannerInfo */
224 typeId[1] = OIDOID; /* operator OID */
225 typeId[2] = INTERNALOID; /* args list */
226 typeId[3] = INT4OID; /* varRelid */
228 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
230 /* estimators must return float8 */
231 if (get_func_rettype(restrictionOid) != FLOAT8OID)
233 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
234 errmsg("restriction estimator function %s must return type \"float8\"",
235 NameListToString(restrictionName))));
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));
244 restrictionOid = InvalidOid;
247 * Look up join estimator if specified
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 */
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.
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);
269 /* estimators must return float8 */
270 if (get_func_rettype(joinOid) != FLOAT8OID)
272 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
273 errmsg("join estimator function %s must return type \"float8\"",
274 NameListToString(joinName))));
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));
283 joinOid = InvalidOid;
286 * now have OperatorCreate do all the work..
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 */
303 * Guts of operator deletion.
306 RemoveOperatorById(Oid operOid)
311 relation = heap_open(OperatorRelationId, RowExclusiveLock);
313 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
314 if (!HeapTupleIsValid(tup)) /* should not happen */
315 elog(ERROR, "cache lookup failed for operator %u", operOid);
317 simple_heap_delete(relation, &tup->t_self);
319 ReleaseSysCache(tup);
321 heap_close(relation, RowExclusiveLock);