1 /*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.24 2005/07/14 21:46:29 tgl Exp $
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 "commands/defrem.h"
43 #include "miscadmin.h"
44 #include "parser/parse_oper.h"
45 #include "parser/parse_type.h"
46 #include "utils/acl.h"
47 #include "utils/lsyscache.h"
48 #include "utils/syscache.h"
53 * this function extracts all the information from the
54 * parameter list generated by the parser and then has
55 * OperatorCreate() do all the actual work.
57 * 'parameters' is a list of DefElem
60 DefineOperator(List *names, List *parameters)
65 bool canHash = false; /* operator hashes */
66 bool canMerge = false; /* operator merges */
67 List *functionName = NIL; /* function for operator */
68 TypeName *typeName1 = NULL; /* first type name */
69 TypeName *typeName2 = NULL; /* second type name */
70 Oid typeId1 = InvalidOid; /* types converted to OID */
71 Oid typeId2 = InvalidOid;
72 List *commutatorName = NIL; /* optional commutator operator
74 List *negatorName = NIL; /* optional negator operator name */
75 List *restrictionName = NIL; /* optional restrict. sel.
77 List *joinName = NIL; /* optional join sel. procedure */
78 List *leftSortName = NIL; /* optional left sort operator */
79 List *rightSortName = NIL; /* optional right sort operator */
80 List *ltCompareName = NIL; /* optional < compare operator */
81 List *gtCompareName = NIL; /* optional > compare operator */
84 /* Convert list of names to a name and namespace */
85 oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
87 /* Check we have creation rights in target namespace */
88 aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
89 if (aclresult != ACLCHECK_OK)
90 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
91 get_namespace_name(oprNamespace));
94 * loop over the definition list and extract the information we need.
96 foreach(pl, parameters)
98 DefElem *defel = (DefElem *) lfirst(pl);
100 if (pg_strcasecmp(defel->defname, "leftarg") == 0)
102 typeName1 = defGetTypeName(defel);
103 if (typeName1->setof)
105 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
106 errmsg("setof type not allowed for operator argument")));
108 else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
110 typeName2 = defGetTypeName(defel);
111 if (typeName2->setof)
113 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
114 errmsg("setof type not allowed for operator argument")));
116 else if (pg_strcasecmp(defel->defname, "procedure") == 0)
117 functionName = defGetQualifiedName(defel);
118 else if (pg_strcasecmp(defel->defname, "commutator") == 0)
119 commutatorName = defGetQualifiedName(defel);
120 else if (pg_strcasecmp(defel->defname, "negator") == 0)
121 negatorName = defGetQualifiedName(defel);
122 else if (pg_strcasecmp(defel->defname, "restrict") == 0)
123 restrictionName = defGetQualifiedName(defel);
124 else if (pg_strcasecmp(defel->defname, "join") == 0)
125 joinName = defGetQualifiedName(defel);
126 else if (pg_strcasecmp(defel->defname, "hashes") == 0)
127 canHash = defGetBoolean(defel);
128 else if (pg_strcasecmp(defel->defname, "merges") == 0)
129 canMerge = defGetBoolean(defel);
130 else if (pg_strcasecmp(defel->defname, "sort1") == 0)
131 leftSortName = defGetQualifiedName(defel);
132 else if (pg_strcasecmp(defel->defname, "sort2") == 0)
133 rightSortName = defGetQualifiedName(defel);
134 else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
135 ltCompareName = defGetQualifiedName(defel);
136 else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
137 gtCompareName = defGetQualifiedName(defel);
140 (errcode(ERRCODE_SYNTAX_ERROR),
141 errmsg("operator attribute \"%s\" not recognized",
146 * make sure we have our required definitions
148 if (functionName == NIL)
150 (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
151 errmsg("operator procedure must be specified")));
153 /* Transform type names to type OIDs */
155 typeId1 = typenameTypeId(typeName1);
157 typeId2 = typenameTypeId(typeName2);
160 * If any of the mergejoin support operators were given, then canMerge
161 * is implicit. If canMerge is specified or implicit, fill in default
162 * operator names for any missing mergejoin support operators.
164 if (leftSortName || rightSortName || ltCompareName || gtCompareName)
170 leftSortName = list_make1(makeString("<"));
172 rightSortName = list_make1(makeString("<"));
174 ltCompareName = list_make1(makeString("<"));
176 gtCompareName = list_make1(makeString(">"));
180 * now have OperatorCreate do all the work..
182 OperatorCreate(oprName, /* operator name */
183 oprNamespace, /* namespace */
184 typeId1, /* left type id */
185 typeId2, /* right type id */
186 functionName, /* function for operator */
187 commutatorName, /* optional commutator operator
189 negatorName, /* optional negator operator name */
190 restrictionName, /* optional restrict. sel.
192 joinName, /* optional join sel. procedure name */
193 canHash, /* operator hashes */
194 leftSortName, /* optional left sort operator */
195 rightSortName, /* optional right sort operator */
196 ltCompareName, /* optional < comparison op */
197 gtCompareName); /* optional < comparison op */
203 * Deletes an operator.
206 RemoveOperator(RemoveOperStmt *stmt)
208 List *operatorName = stmt->opname;
209 TypeName *typeName1 = (TypeName *) linitial(stmt->args);
210 TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
213 ObjectAddress object;
215 operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
218 tup = SearchSysCache(OPEROID,
219 ObjectIdGetDatum(operOid),
221 if (!HeapTupleIsValid(tup)) /* should not happen */
222 elog(ERROR, "cache lookup failed for operator %u", operOid);
224 /* Permission check: must own operator or its namespace */
225 if (!pg_oper_ownercheck(operOid, GetUserId()) &&
226 !pg_namespace_ownercheck(((Form_pg_operator) GETSTRUCT(tup))->oprnamespace,
228 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
229 NameListToString(operatorName));
231 ReleaseSysCache(tup);
236 object.classId = OperatorRelationId;
237 object.objectId = operOid;
238 object.objectSubId = 0;
240 performDeletion(&object, stmt->behavior);
244 * Guts of operator deletion.
247 RemoveOperatorById(Oid operOid)
252 relation = heap_open(OperatorRelationId, RowExclusiveLock);
254 tup = SearchSysCache(OPEROID,
255 ObjectIdGetDatum(operOid),
257 if (!HeapTupleIsValid(tup)) /* should not happen */
258 elog(ERROR, "cache lookup failed for operator %u", operOid);
260 simple_heap_delete(relation, &tup->t_self);
262 ReleaseSysCache(tup);
264 heap_close(relation, RowExclusiveLock);
268 * change operator owner
271 AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
278 Form_pg_operator oprForm;
280 rel = heap_open(OperatorRelationId, RowExclusiveLock);
282 operOid = LookupOperNameTypeNames(name, typeName1, typeName2,
285 tup = SearchSysCacheCopy(OPEROID,
286 ObjectIdGetDatum(operOid),
288 if (!HeapTupleIsValid(tup)) /* should not happen */
289 elog(ERROR, "cache lookup failed for operator %u", operOid);
291 oprForm = (Form_pg_operator) GETSTRUCT(tup);
294 * If the new owner is the same as the existing owner, consider the
295 * command to have succeeded. This is for dump restoration purposes.
297 if (oprForm->oprowner != newOwnerId)
299 /* Otherwise, must be owner of the existing object */
300 if (!pg_oper_ownercheck(operOid,GetUserId()))
301 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
302 NameListToString(name));
304 /* Must be able to become new owner */
305 check_is_member_of_role(GetUserId(), newOwnerId);
307 /* New owner must have CREATE privilege on namespace */
308 aclresult = pg_namespace_aclcheck(oprForm->oprnamespace, newOwnerId,
310 if (aclresult != ACLCHECK_OK)
311 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
312 get_namespace_name(oprForm->oprnamespace));
315 * Modify the owner --- okay to scribble on tup because it's a
318 oprForm->oprowner = newOwnerId;
320 simple_heap_update(rel, &tup->t_self, tup);
322 CatalogUpdateIndexes(rel, tup);
324 /* Update owner dependency reference */
325 changeDependencyOnOwner(OperatorRelationId, operOid, newOwnerId);
328 heap_close(rel, NoLock);