~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/commands/operatorcmds.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * operatorcmds.c
 
4
 *
 
5
 *        Routines for operator manipulation commands
 
6
 *
 
7
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
8
 * Portions Copyright (c) 1994, Regents of the University of California
 
9
 *
 
10
 *
 
11
 * IDENTIFICATION
 
12
 *        $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.20 2004-12-31 21:59:41 pgsql Exp $
 
13
 *
 
14
 * DESCRIPTION
 
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.
 
20
 *
 
21
 * NOTES
 
22
 *        These things must be defined and committed in the following order:
 
23
 *              "create function":
 
24
 *                              input/output, recv/send procedures
 
25
 *              "create type":
 
26
 *                              type
 
27
 *              "create operator":
 
28
 *                              operators
 
29
 *
 
30
 *              Most of the parse-tree manipulation routines are defined in
 
31
 *              commands/manip.c.
 
32
 *
 
33
 *-------------------------------------------------------------------------
 
34
 */
 
35
#include "postgres.h"
 
36
 
 
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"
 
50
 
 
51
 
 
52
/*
 
53
 * DefineOperator
 
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.
 
57
 *
 
58
 * 'parameters' is a list of DefElem
 
59
 */
 
60
void
 
61
DefineOperator(List *names, List *parameters)
 
62
{
 
63
        char       *oprName;
 
64
        Oid                     oprNamespace;
 
65
        AclResult       aclresult;
 
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
 
74
                                                                                 * name */
 
75
        List       *negatorName = NIL;          /* optional negator operator name */
 
76
        List       *restrictionName = NIL;      /* optional restrict. sel.
 
77
                                                                                 * procedure */
 
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 */
 
83
        ListCell   *pl;
 
84
 
 
85
        /* Convert list of names to a name and namespace */
 
86
        oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
 
87
 
 
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));
 
93
 
 
94
        /*
 
95
         * loop over the definition list and extract the information we need.
 
96
         */
 
97
        foreach(pl, parameters)
 
98
        {
 
99
                DefElem    *defel = (DefElem *) lfirst(pl);
 
100
 
 
101
                if (pg_strcasecmp(defel->defname, "leftarg") == 0)
 
102
                {
 
103
                        typeName1 = defGetTypeName(defel);
 
104
                        if (typeName1->setof)
 
105
                                ereport(ERROR,
 
106
                                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
107
                                errmsg("setof type not allowed for operator argument")));
 
108
                }
 
109
                else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
 
110
                {
 
111
                        typeName2 = defGetTypeName(defel);
 
112
                        if (typeName2->setof)
 
113
                                ereport(ERROR,
 
114
                                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
115
                                errmsg("setof type not allowed for operator argument")));
 
116
                }
 
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);
 
139
                else
 
140
                        ereport(WARNING,
 
141
                                        (errcode(ERRCODE_SYNTAX_ERROR),
 
142
                                         errmsg("operator attribute \"%s\" not recognized",
 
143
                                                        defel->defname)));
 
144
        }
 
145
 
 
146
        /*
 
147
         * make sure we have our required definitions
 
148
         */
 
149
        if (functionName == NIL)
 
150
                ereport(ERROR,
 
151
                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
152
                                 errmsg("operator procedure must be specified")));
 
153
 
 
154
        /* Transform type names to type OIDs */
 
155
        if (typeName1)
 
156
                typeId1 = typenameTypeId(typeName1);
 
157
        if (typeName2)
 
158
                typeId2 = typenameTypeId(typeName2);
 
159
 
 
160
        /*
 
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.
 
164
         */
 
165
        if (leftSortName || rightSortName || ltCompareName || gtCompareName)
 
166
                canMerge = true;
 
167
 
 
168
        if (canMerge)
 
169
        {
 
170
                if (!leftSortName)
 
171
                        leftSortName = list_make1(makeString("<"));
 
172
                if (!rightSortName)
 
173
                        rightSortName = list_make1(makeString("<"));
 
174
                if (!ltCompareName)
 
175
                        ltCompareName = list_make1(makeString("<"));
 
176
                if (!gtCompareName)
 
177
                        gtCompareName = list_make1(makeString(">"));
 
178
        }
 
179
 
 
180
        /*
 
181
         * now have OperatorCreate do all the work..
 
182
         */
 
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
 
189
                                                                                 * name */
 
190
                                   negatorName, /* optional negator operator name */
 
191
                                   restrictionName,             /* optional restrict. sel.
 
192
                                                                                 * procedure */
 
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 */
 
199
}
 
200
 
 
201
 
 
202
/*
 
203
 * RemoveOperator
 
204
 *              Deletes an operator.
 
205
 */
 
206
void
 
207
RemoveOperator(RemoveOperStmt *stmt)
 
208
{
 
209
        List       *operatorName = stmt->opname;
 
210
        TypeName   *typeName1 = (TypeName *) linitial(stmt->args);
 
211
        TypeName   *typeName2 = (TypeName *) lsecond(stmt->args);
 
212
        Oid                     operOid;
 
213
        HeapTuple       tup;
 
214
        ObjectAddress object;
 
215
 
 
216
        operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
 
217
                                                                          false);
 
218
 
 
219
        tup = SearchSysCache(OPEROID,
 
220
                                                 ObjectIdGetDatum(operOid),
 
221
                                                 0, 0, 0);
 
222
        if (!HeapTupleIsValid(tup)) /* should not happen */
 
223
                elog(ERROR, "cache lookup failed for operator %u", operOid);
 
224
 
 
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,
 
228
                                                                 GetUserId()))
 
229
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
 
230
                                           NameListToString(operatorName));
 
231
 
 
232
        ReleaseSysCache(tup);
 
233
 
 
234
        /*
 
235
         * Do the deletion
 
236
         */
 
237
        object.classId = get_system_catalog_relid(OperatorRelationName);
 
238
        object.objectId = operOid;
 
239
        object.objectSubId = 0;
 
240
 
 
241
        performDeletion(&object, stmt->behavior);
 
242
}
 
243
 
 
244
/*
 
245
 * Guts of operator deletion.
 
246
 */
 
247
void
 
248
RemoveOperatorById(Oid operOid)
 
249
{
 
250
        Relation        relation;
 
251
        HeapTuple       tup;
 
252
 
 
253
        relation = heap_openr(OperatorRelationName, RowExclusiveLock);
 
254
 
 
255
        tup = SearchSysCache(OPEROID,
 
256
                                                 ObjectIdGetDatum(operOid),
 
257
                                                 0, 0, 0);
 
258
        if (!HeapTupleIsValid(tup)) /* should not happen */
 
259
                elog(ERROR, "cache lookup failed for operator %u", operOid);
 
260
 
 
261
        simple_heap_delete(relation, &tup->t_self);
 
262
 
 
263
        ReleaseSysCache(tup);
 
264
 
 
265
        heap_close(relation, RowExclusiveLock);
 
266
}
 
267
 
 
268
/*
 
269
 * change operator owner
 
270
 */
 
271
void
 
272
AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 
273
                                   AclId newOwnerSysId)
 
274
{
 
275
        Oid                     operOid;
 
276
        HeapTuple       tup;
 
277
        Relation        rel;
 
278
        Form_pg_operator oprForm;
 
279
 
 
280
        rel = heap_openr(OperatorRelationName, RowExclusiveLock);
 
281
 
 
282
        operOid = LookupOperNameTypeNames(name, typeName1, typeName2,
 
283
                                                                          false);
 
284
 
 
285
        tup = SearchSysCacheCopy(OPEROID,
 
286
                                                         ObjectIdGetDatum(operOid),
 
287
                                                         0, 0, 0);
 
288
        if (!HeapTupleIsValid(tup)) /* should not happen */
 
289
                elog(ERROR, "cache lookup failed for operator %u", operOid);
 
290
 
 
291
        oprForm = (Form_pg_operator) GETSTRUCT(tup);
 
292
 
 
293
        /*
 
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.
 
296
         */
 
297
        if (oprForm->oprowner != newOwnerSysId)
 
298
        {
 
299
                /* Otherwise, must be superuser to change object ownership */
 
300
                if (!superuser())
 
301
                        ereport(ERROR,
 
302
                                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 
303
                                         errmsg("must be superuser to change owner")));
 
304
 
 
305
                /*
 
306
                 * Modify the owner --- okay to scribble on tup because it's a
 
307
                 * copy
 
308
                 */
 
309
                oprForm->oprowner = newOwnerSysId;
 
310
 
 
311
                simple_heap_update(rel, &tup->t_self, tup);
 
312
 
 
313
                CatalogUpdateIndexes(rel, tup);
 
314
        }
 
315
 
 
316
        heap_close(rel, NoLock);
 
317
        heap_freetuple(tup);
 
318
 
 
319
}