1 /*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2010, 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 "catalog/dependency.h"
39 #include "catalog/indexing.h"
40 #include "catalog/namespace.h"
41 #include "catalog/pg_operator.h"
42 #include "catalog/pg_type.h"
43 #include "commands/defrem.h"
44 #include "miscadmin.h"
45 #include "parser/parse_func.h"
46 #include "parser/parse_oper.h"
47 #include "parser/parse_type.h"
48 #include "utils/acl.h"
49 #include "utils/lsyscache.h"
50 #include "utils/rel.h"
51 #include "utils/syscache.h"
54 static void AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId);
58 * this function extracts all the information from the
59 * parameter list generated by the parser and then has
60 * OperatorCreate() do all the actual work.
62 * 'parameters' is a list of DefElem
65 DefineOperator(List *names, List *parameters)
70 bool canMerge = false; /* operator merges */
71 bool canHash = false; /* operator hashes */
72 List *functionName = NIL; /* function for operator */
73 TypeName *typeName1 = NULL; /* first type name */
74 TypeName *typeName2 = NULL; /* second type name */
75 Oid typeId1 = InvalidOid; /* types converted to OID */
76 Oid typeId2 = InvalidOid;
77 List *commutatorName = NIL; /* optional commutator operator name */
78 List *negatorName = NIL; /* optional negator operator name */
79 List *restrictionName = NIL; /* optional restrict. sel. procedure */
80 List *joinName = NIL; /* optional join sel. procedure */
81 Oid functionOid; /* functions converted to OID */
84 Oid typeId[5]; /* only need up to 5 args here */
88 /* Convert list of names to a name and namespace */
89 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
92 * The SQL standard committee has decided that => should be used for named
93 * parameters; therefore, a future release of PostgreSQL may disallow it
94 * as the name of a user-defined operator.
96 if (strcmp(oprName, "=>") == 0)
98 (errmsg("=> is deprecated as an operator name"),
99 errdetail("This name may be disallowed altogether in future versions of PostgreSQL.")));
101 /* Check we have creation rights in target namespace */
102 aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
103 if (aclresult != ACLCHECK_OK)
104 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
105 get_namespace_name(oprNamespace));
108 * loop over the definition list and extract the information we need.
110 foreach(pl, parameters)
112 DefElem *defel = (DefElem *) lfirst(pl);
114 if (pg_strcasecmp(defel->defname, "leftarg") == 0)
116 typeName1 = defGetTypeName(defel);
117 if (typeName1->setof)
119 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
120 errmsg("SETOF type not allowed for operator argument")));
122 else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
124 typeName2 = defGetTypeName(defel);
125 if (typeName2->setof)
127 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
128 errmsg("SETOF type not allowed for operator argument")));
130 else if (pg_strcasecmp(defel->defname, "procedure") == 0)
131 functionName = defGetQualifiedName(defel);
132 else if (pg_strcasecmp(defel->defname, "commutator") == 0)
133 commutatorName = defGetQualifiedName(defel);
134 else if (pg_strcasecmp(defel->defname, "negator") == 0)
135 negatorName = defGetQualifiedName(defel);
136 else if (pg_strcasecmp(defel->defname, "restrict") == 0)
137 restrictionName = defGetQualifiedName(defel);
138 else if (pg_strcasecmp(defel->defname, "join") == 0)
139 joinName = defGetQualifiedName(defel);
140 else if (pg_strcasecmp(defel->defname, "hashes") == 0)
141 canHash = defGetBoolean(defel);
142 else if (pg_strcasecmp(defel->defname, "merges") == 0)
143 canMerge = defGetBoolean(defel);
144 /* These obsolete options are taken as meaning canMerge */
145 else if (pg_strcasecmp(defel->defname, "sort1") == 0)
147 else if (pg_strcasecmp(defel->defname, "sort2") == 0)
149 else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
151 else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
155 (errcode(ERRCODE_SYNTAX_ERROR),
156 errmsg("operator attribute \"%s\" not recognized",
161 * make sure we have our required definitions
163 if (functionName == NIL)
165 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
166 errmsg("operator procedure must be specified")));
168 /* Transform type names to type OIDs */
170 typeId1 = typenameTypeId(NULL, typeName1);
172 typeId2 = typenameTypeId(NULL, typeName2);
174 if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
176 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
177 errmsg("at least one of leftarg or rightarg must be specified")));
180 * Look up the operator's underlying function.
182 if (!OidIsValid(typeId1))
187 else if (!OidIsValid(typeId2))
198 functionOid = LookupFuncName(functionName, nargs, typeId, false);
201 * We require EXECUTE rights for the function. This isn't strictly
202 * necessary, since EXECUTE will be checked at any attempted use of the
203 * operator, but it seems like a good idea anyway.
205 aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
206 if (aclresult != ACLCHECK_OK)
207 aclcheck_error(aclresult, ACL_KIND_PROC,
208 NameListToString(functionName));
211 * Look up restriction estimator if specified
215 typeId[0] = INTERNALOID; /* PlannerInfo */
216 typeId[1] = OIDOID; /* operator OID */
217 typeId[2] = INTERNALOID; /* args list */
218 typeId[3] = INT4OID; /* varRelid */
220 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
222 /* estimators must return float8 */
223 if (get_func_rettype(restrictionOid) != FLOAT8OID)
225 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
226 errmsg("restriction estimator function %s must return type \"float8\"",
227 NameListToString(restrictionName))));
229 /* Require EXECUTE rights for the estimator */
230 aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
231 if (aclresult != ACLCHECK_OK)
232 aclcheck_error(aclresult, ACL_KIND_PROC,
233 NameListToString(restrictionName));
236 restrictionOid = InvalidOid;
239 * Look up join estimator if specified
243 typeId[0] = INTERNALOID; /* PlannerInfo */
244 typeId[1] = OIDOID; /* operator OID */
245 typeId[2] = INTERNALOID; /* args list */
246 typeId[3] = INT2OID; /* jointype */
247 typeId[4] = INTERNALOID; /* SpecialJoinInfo */
250 * As of Postgres 8.4, the preferred signature for join estimators has
251 * 5 arguments, but we still allow the old 4-argument form. Try the
252 * preferred form first.
254 joinOid = LookupFuncName(joinName, 5, typeId, true);
255 if (!OidIsValid(joinOid))
256 joinOid = LookupFuncName(joinName, 4, typeId, true);
257 /* If not found, reference the 5-argument signature in error msg */
258 if (!OidIsValid(joinOid))
259 joinOid = LookupFuncName(joinName, 5, typeId, false);
261 /* estimators must return float8 */
262 if (get_func_rettype(joinOid) != FLOAT8OID)
264 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265 errmsg("join estimator function %s must return type \"float8\"",
266 NameListToString(joinName))));
268 /* Require EXECUTE rights for the estimator */
269 aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
270 if (aclresult != ACLCHECK_OK)
271 aclcheck_error(aclresult, ACL_KIND_PROC,
272 NameListToString(joinName));
275 joinOid = InvalidOid;
278 * now have OperatorCreate do all the work..
280 OperatorCreate(oprName, /* operator name */
281 oprNamespace, /* namespace */
282 typeId1, /* left type id */
283 typeId2, /* right type id */
284 functionOid, /* function for operator */
285 commutatorName, /* optional commutator operator name */
286 negatorName, /* optional negator operator name */
287 restrictionOid, /* optional restrict. sel. procedure */
288 joinOid, /* optional join sel. procedure name */
289 canMerge, /* operator merges */
290 canHash); /* operator hashes */
296 * Deletes an operator.
299 RemoveOperator(RemoveFuncStmt *stmt)
301 List *operatorName = stmt->name;
302 TypeName *typeName1 = (TypeName *) linitial(stmt->args);
303 TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
306 ObjectAddress object;
308 Assert(list_length(stmt->args) == 2);
309 operOid = LookupOperNameTypeNames(NULL, operatorName,
310 typeName1, typeName2,
311 stmt->missing_ok, -1);
313 if (stmt->missing_ok && !OidIsValid(operOid))
316 (errmsg("operator %s does not exist, skipping",
317 NameListToString(operatorName))));
321 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
322 if (!HeapTupleIsValid(tup)) /* should not happen */
323 elog(ERROR, "cache lookup failed for operator %u", operOid);
325 /* Permission check: must own operator or its namespace */
326 if (!pg_oper_ownercheck(operOid, GetUserId()) &&
327 !pg_namespace_ownercheck(((Form_pg_operator) GETSTRUCT(tup))->oprnamespace,
329 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
330 NameListToString(operatorName));
332 ReleaseSysCache(tup);
337 object.classId = OperatorRelationId;
338 object.objectId = operOid;
339 object.objectSubId = 0;
341 performDeletion(&object, stmt->behavior);
345 * Guts of operator deletion.
348 RemoveOperatorById(Oid operOid)
353 relation = heap_open(OperatorRelationId, RowExclusiveLock);
355 tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
356 if (!HeapTupleIsValid(tup)) /* should not happen */
357 elog(ERROR, "cache lookup failed for operator %u", operOid);
359 simple_heap_delete(relation, &tup->t_self);
361 ReleaseSysCache(tup);
363 heap_close(relation, RowExclusiveLock);
367 AlterOperatorOwner_oid(Oid operOid, Oid newOwnerId)
371 rel = heap_open(OperatorRelationId, RowExclusiveLock);
373 AlterOperatorOwner_internal(rel, operOid, newOwnerId);
375 heap_close(rel, NoLock);
379 * change operator owner
382 AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
388 rel = heap_open(OperatorRelationId, RowExclusiveLock);
390 operOid = LookupOperNameTypeNames(NULL, name,
391 typeName1, typeName2,
394 AlterOperatorOwner_internal(rel, operOid, newOwnerId);
396 heap_close(rel, NoLock);
400 AlterOperatorOwner_internal(Relation rel, Oid operOid, Oid newOwnerId)
404 Form_pg_operator oprForm;
406 Assert(RelationGetRelid(rel) == OperatorRelationId);
408 tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(operOid));
409 if (!HeapTupleIsValid(tup)) /* should not happen */
410 elog(ERROR, "cache lookup failed for operator %u", operOid);
412 oprForm = (Form_pg_operator) GETSTRUCT(tup);
415 * If the new owner is the same as the existing owner, consider the
416 * command to have succeeded. This is for dump restoration purposes.
418 if (oprForm->oprowner != newOwnerId)
420 /* Superusers can always do it */
423 /* Otherwise, must be owner of the existing object */
424 if (!pg_oper_ownercheck(operOid, GetUserId()))
425 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
426 NameStr(oprForm->oprname));
428 /* Must be able to become new owner */
429 check_is_member_of_role(GetUserId(), newOwnerId);
431 /* New owner must have CREATE privilege on namespace */
432 aclresult = pg_namespace_aclcheck(oprForm->oprnamespace,
435 if (aclresult != ACLCHECK_OK)
436 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
437 get_namespace_name(oprForm->oprnamespace));
441 * Modify the owner --- okay to scribble on tup because it's a copy
443 oprForm->oprowner = newOwnerId;
445 simple_heap_update(rel, &tup->t_self, tup);
447 CatalogUpdateIndexes(rel, tup);
449 /* Update owner dependency reference */
450 changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);