1 /*-------------------------------------------------------------------------
5 * Routines for operator manipulation commands
7 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
12 * $Header: /cvsroot/pgsql/src/backend/commands/operatorcmds.c,v 1.5 2002/07/12 18:43:16 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/catname.h"
39 #include "catalog/dependency.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 uint16 precedence = 0; /* operator precedence */
66 bool canHash = false; /* operator hashes */
67 bool canMerge = false; /* operator merges */
68 bool isLeftAssociative = true; /* operator is left
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 List *commutatorName = NIL; /* optional commutator operator
77 List *negatorName = NIL; /* optional negator operator name */
78 List *restrictionName = NIL; /* optional restrict. sel.
80 List *joinName = NIL; /* optional join sel. procedure */
81 List *leftSortName = NIL; /* optional left sort operator */
82 List *rightSortName = NIL; /* optional right sort operator */
83 List *ltCompareName = NIL; /* optional < compare operator */
84 List *gtCompareName = NIL; /* optional > compare operator */
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, get_namespace_name(oprNamespace));
96 * loop over the definition list and extract the information we need.
98 foreach(pl, parameters)
100 DefElem *defel = (DefElem *) lfirst(pl);
102 if (strcasecmp(defel->defname, "leftarg") == 0)
104 typeName1 = defGetTypeName(defel);
105 if (typeName1->setof)
106 elog(ERROR, "setof type not implemented for leftarg");
108 else if (strcasecmp(defel->defname, "rightarg") == 0)
110 typeName2 = defGetTypeName(defel);
111 if (typeName2->setof)
112 elog(ERROR, "setof type not implemented for rightarg");
114 else if (strcasecmp(defel->defname, "procedure") == 0)
115 functionName = defGetQualifiedName(defel);
116 else if (strcasecmp(defel->defname, "precedence") == 0)
118 /* NOT IMPLEMENTED (never worked in v4.2) */
119 elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
121 else if (strcasecmp(defel->defname, "associativity") == 0)
123 /* NOT IMPLEMENTED (never worked in v4.2) */
124 elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
126 else if (strcasecmp(defel->defname, "commutator") == 0)
127 commutatorName = defGetQualifiedName(defel);
128 else if (strcasecmp(defel->defname, "negator") == 0)
129 negatorName = defGetQualifiedName(defel);
130 else if (strcasecmp(defel->defname, "restrict") == 0)
131 restrictionName = defGetQualifiedName(defel);
132 else if (strcasecmp(defel->defname, "join") == 0)
133 joinName = defGetQualifiedName(defel);
134 else if (strcasecmp(defel->defname, "hashes") == 0)
136 else if (strcasecmp(defel->defname, "merges") == 0)
138 else if (strcasecmp(defel->defname, "sort1") == 0)
139 leftSortName = defGetQualifiedName(defel);
140 else if (strcasecmp(defel->defname, "sort2") == 0)
141 rightSortName = defGetQualifiedName(defel);
142 else if (strcasecmp(defel->defname, "ltcmp") == 0)
143 ltCompareName = defGetQualifiedName(defel);
144 else if (strcasecmp(defel->defname, "gtcmp") == 0)
145 gtCompareName = defGetQualifiedName(defel);
148 elog(WARNING, "DefineOperator: attribute \"%s\" not recognized",
154 * make sure we have our required definitions
156 if (functionName == NIL)
157 elog(ERROR, "Define: \"procedure\" unspecified");
159 /* Transform type names to type OIDs */
161 typeId1 = typenameTypeId(typeName1);
163 typeId2 = typenameTypeId(typeName2);
166 * If any of the mergejoin support operators were given, then canMerge
167 * is implicit. If canMerge is specified or implicit, fill in default
168 * operator names for any missing mergejoin support operators.
170 if (leftSortName || rightSortName || ltCompareName || gtCompareName)
176 leftSortName = makeList1(makeString("<"));
178 rightSortName = makeList1(makeString("<"));
180 ltCompareName = makeList1(makeString("<"));
182 gtCompareName = makeList1(makeString(">"));
186 * now have OperatorCreate do all the work..
188 OperatorCreate(oprName, /* operator name */
189 oprNamespace, /* namespace */
190 typeId1, /* left type id */
191 typeId2, /* right type id */
192 functionName, /* function for operator */
193 precedence, /* operator precedence */
194 isLeftAssociative, /* operator is left associative */
195 commutatorName, /* optional commutator operator
197 negatorName, /* optional negator operator name */
198 restrictionName, /* optional restrict. sel.
200 joinName, /* optional join sel. procedure name */
201 canHash, /* operator hashes */
202 leftSortName, /* optional left sort operator */
203 rightSortName, /* optional right sort operator */
204 ltCompareName, /* optional < comparison op */
205 gtCompareName); /* optional < comparison op */
211 * Deletes an operator.
214 RemoveOperator(RemoveOperStmt *stmt)
216 List *operatorName = stmt->opname;
217 TypeName *typeName1 = (TypeName *) lfirst(stmt->args);
218 TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
221 ObjectAddress object;
223 operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
226 tup = SearchSysCache(OPEROID,
227 ObjectIdGetDatum(operOid),
229 if (!HeapTupleIsValid(tup)) /* should not happen */
230 elog(ERROR, "RemoveOperator: failed to find tuple for operator '%s'",
231 NameListToString(operatorName));
233 /* Permission check: must own operator or its namespace */
234 if (!pg_oper_ownercheck(operOid, GetUserId()) &&
235 !pg_namespace_ownercheck(((Form_pg_operator) GETSTRUCT(tup))->oprnamespace,
237 aclcheck_error(ACLCHECK_NOT_OWNER, NameListToString(operatorName));
239 ReleaseSysCache(tup);
244 object.classId = get_system_catalog_relid(OperatorRelationName);
245 object.objectId = operOid;
246 object.objectSubId = 0;
248 performDeletion(&object, stmt->behavior);
252 * Guts of operator deletion.
255 RemoveOperatorById(Oid operOid)
260 relation = heap_openr(OperatorRelationName, RowExclusiveLock);
262 tup = SearchSysCache(OPEROID,
263 ObjectIdGetDatum(operOid),
265 if (!HeapTupleIsValid(tup)) /* should not happen */
266 elog(ERROR, "RemoveOperatorById: failed to find tuple for operator %u",
269 simple_heap_delete(relation, &tup->t_self);
271 ReleaseSysCache(tup);
273 heap_close(relation, RowExclusiveLock);