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.20 2004-12-31 21:59:41 pgsql 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/indexing.h"
41
#include "catalog/namespace.h"
42
#include "catalog/pg_operator.h"
43
#include "commands/defrem.h"
44
#include "miscadmin.h"
45
#include "parser/parse_oper.h"
46
#include "parser/parse_type.h"
47
#include "utils/acl.h"
48
#include "utils/lsyscache.h"
49
#include "utils/syscache.h"
54
* this function extracts all the information from the
55
* parameter list generated by the parser and then has
56
* OperatorCreate() do all the actual work.
58
* 'parameters' is a list of DefElem
61
DefineOperator(List *names, List *parameters)
66
bool canHash = false; /* operator hashes */
67
bool canMerge = false; /* operator merges */
68
List *functionName = NIL; /* function for operator */
69
TypeName *typeName1 = NULL; /* first type name */
70
TypeName *typeName2 = NULL; /* second type name */
71
Oid typeId1 = InvalidOid; /* types converted to OID */
72
Oid typeId2 = InvalidOid;
73
List *commutatorName = NIL; /* optional commutator operator
75
List *negatorName = NIL; /* optional negator operator name */
76
List *restrictionName = NIL; /* optional restrict. sel.
78
List *joinName = NIL; /* optional join sel. procedure */
79
List *leftSortName = NIL; /* optional left sort operator */
80
List *rightSortName = NIL; /* optional right sort operator */
81
List *ltCompareName = NIL; /* optional < compare operator */
82
List *gtCompareName = NIL; /* optional > compare operator */
85
/* Convert list of names to a name and namespace */
86
oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
88
/* Check we have creation rights in target namespace */
89
aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
90
if (aclresult != ACLCHECK_OK)
91
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
92
get_namespace_name(oprNamespace));
95
* loop over the definition list and extract the information we need.
97
foreach(pl, parameters)
99
DefElem *defel = (DefElem *) lfirst(pl);
101
if (pg_strcasecmp(defel->defname, "leftarg") == 0)
103
typeName1 = defGetTypeName(defel);
104
if (typeName1->setof)
106
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
107
errmsg("setof type not allowed for operator argument")));
109
else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
111
typeName2 = defGetTypeName(defel);
112
if (typeName2->setof)
114
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
115
errmsg("setof type not allowed for operator argument")));
117
else if (pg_strcasecmp(defel->defname, "procedure") == 0)
118
functionName = defGetQualifiedName(defel);
119
else if (pg_strcasecmp(defel->defname, "commutator") == 0)
120
commutatorName = defGetQualifiedName(defel);
121
else if (pg_strcasecmp(defel->defname, "negator") == 0)
122
negatorName = defGetQualifiedName(defel);
123
else if (pg_strcasecmp(defel->defname, "restrict") == 0)
124
restrictionName = defGetQualifiedName(defel);
125
else if (pg_strcasecmp(defel->defname, "join") == 0)
126
joinName = defGetQualifiedName(defel);
127
else if (pg_strcasecmp(defel->defname, "hashes") == 0)
128
canHash = defGetBoolean(defel);
129
else if (pg_strcasecmp(defel->defname, "merges") == 0)
130
canMerge = defGetBoolean(defel);
131
else if (pg_strcasecmp(defel->defname, "sort1") == 0)
132
leftSortName = defGetQualifiedName(defel);
133
else if (pg_strcasecmp(defel->defname, "sort2") == 0)
134
rightSortName = defGetQualifiedName(defel);
135
else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
136
ltCompareName = defGetQualifiedName(defel);
137
else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
138
gtCompareName = defGetQualifiedName(defel);
141
(errcode(ERRCODE_SYNTAX_ERROR),
142
errmsg("operator attribute \"%s\" not recognized",
147
* make sure we have our required definitions
149
if (functionName == NIL)
151
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
152
errmsg("operator procedure must be specified")));
154
/* Transform type names to type OIDs */
156
typeId1 = typenameTypeId(typeName1);
158
typeId2 = typenameTypeId(typeName2);
161
* If any of the mergejoin support operators were given, then canMerge
162
* is implicit. If canMerge is specified or implicit, fill in default
163
* operator names for any missing mergejoin support operators.
165
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
171
leftSortName = list_make1(makeString("<"));
173
rightSortName = list_make1(makeString("<"));
175
ltCompareName = list_make1(makeString("<"));
177
gtCompareName = list_make1(makeString(">"));
181
* now have OperatorCreate do all the work..
183
OperatorCreate(oprName, /* operator name */
184
oprNamespace, /* namespace */
185
typeId1, /* left type id */
186
typeId2, /* right type id */
187
functionName, /* function for operator */
188
commutatorName, /* optional commutator operator
190
negatorName, /* optional negator operator name */
191
restrictionName, /* optional restrict. sel.
193
joinName, /* optional join sel. procedure name */
194
canHash, /* operator hashes */
195
leftSortName, /* optional left sort operator */
196
rightSortName, /* optional right sort operator */
197
ltCompareName, /* optional < comparison op */
198
gtCompareName); /* optional < comparison op */
204
* Deletes an operator.
207
RemoveOperator(RemoveOperStmt *stmt)
209
List *operatorName = stmt->opname;
210
TypeName *typeName1 = (TypeName *) linitial(stmt->args);
211
TypeName *typeName2 = (TypeName *) lsecond(stmt->args);
214
ObjectAddress object;
216
operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
219
tup = SearchSysCache(OPEROID,
220
ObjectIdGetDatum(operOid),
222
if (!HeapTupleIsValid(tup)) /* should not happen */
223
elog(ERROR, "cache lookup failed for operator %u", operOid);
225
/* Permission check: must own operator or its namespace */
226
if (!pg_oper_ownercheck(operOid, GetUserId()) &&
227
!pg_namespace_ownercheck(((Form_pg_operator) GETSTRUCT(tup))->oprnamespace,
229
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
230
NameListToString(operatorName));
232
ReleaseSysCache(tup);
237
object.classId = get_system_catalog_relid(OperatorRelationName);
238
object.objectId = operOid;
239
object.objectSubId = 0;
241
performDeletion(&object, stmt->behavior);
245
* Guts of operator deletion.
248
RemoveOperatorById(Oid operOid)
253
relation = heap_openr(OperatorRelationName, RowExclusiveLock);
255
tup = SearchSysCache(OPEROID,
256
ObjectIdGetDatum(operOid),
258
if (!HeapTupleIsValid(tup)) /* should not happen */
259
elog(ERROR, "cache lookup failed for operator %u", operOid);
261
simple_heap_delete(relation, &tup->t_self);
263
ReleaseSysCache(tup);
265
heap_close(relation, RowExclusiveLock);
269
* change operator owner
272
AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
278
Form_pg_operator oprForm;
280
rel = heap_openr(OperatorRelationName, 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 != newOwnerSysId)
299
/* Otherwise, must be superuser to change object ownership */
302
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
303
errmsg("must be superuser to change owner")));
306
* Modify the owner --- okay to scribble on tup because it's a
309
oprForm->oprowner = newOwnerSysId;
311
simple_heap_update(rel, &tup->t_self, tup);
313
CatalogUpdateIndexes(rel, tup);
316
heap_close(rel, NoLock);