~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to src/backend/catalog/pg_operator.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
 * pg_operator.c
 
4
 *        routines to support manipulation of the pg_operator relation
 
5
 *
 
6
 * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.87 2004-12-31 21:59:38 pgsql Exp $
 
12
 *
 
13
 * NOTES
 
14
 *        these routines moved here from commands/define.c and somewhat cleaned up.
 
15
 *
 
16
 *-------------------------------------------------------------------------
 
17
 */
 
18
#include "postgres.h"
 
19
 
 
20
#include "access/heapam.h"
 
21
#include "catalog/catname.h"
 
22
#include "catalog/dependency.h"
 
23
#include "catalog/indexing.h"
 
24
#include "catalog/namespace.h"
 
25
#include "catalog/pg_operator.h"
 
26
#include "catalog/pg_type.h"
 
27
#include "miscadmin.h"
 
28
#include "parser/parse_func.h"
 
29
#include "parser/parse_oper.h"
 
30
#include "utils/acl.h"
 
31
#include "utils/builtins.h"
 
32
#include "utils/lsyscache.h"
 
33
#include "utils/syscache.h"
 
34
 
 
35
 
 
36
static Oid OperatorGet(const char *operatorName,
 
37
                        Oid operatorNamespace,
 
38
                        Oid leftObjectId,
 
39
                        Oid rightObjectId,
 
40
                        bool *defined);
 
41
 
 
42
static Oid OperatorLookup(List *operatorName,
 
43
                           Oid leftObjectId,
 
44
                           Oid rightObjectId,
 
45
                           bool *defined);
 
46
 
 
47
static Oid OperatorShellMake(const char *operatorName,
 
48
                                  Oid operatorNamespace,
 
49
                                  Oid leftTypeId,
 
50
                                  Oid rightTypeId);
 
51
 
 
52
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
 
53
 
 
54
static Oid get_other_operator(List *otherOp,
 
55
                                   Oid otherLeftTypeId, Oid otherRightTypeId,
 
56
                                   const char *operatorName, Oid operatorNamespace,
 
57
                                   Oid leftTypeId, Oid rightTypeId,
 
58
                                   bool isCommutator);
 
59
 
 
60
static void makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid);
 
61
 
 
62
 
 
63
/*
 
64
 * Check whether a proposed operator name is legal
 
65
 *
 
66
 * This had better match the behavior of parser/scan.l!
 
67
 *
 
68
 * We need this because the parser is not smart enough to check that
 
69
 * the arguments of CREATE OPERATOR's COMMUTATOR, NEGATOR, etc clauses
 
70
 * are operator names rather than some other lexical entity.
 
71
 */
 
72
static bool
 
73
validOperatorName(const char *name)
 
74
{
 
75
        size_t          len = strlen(name);
 
76
 
 
77
        /* Can't be empty or too long */
 
78
        if (len == 0 || len >= NAMEDATALEN)
 
79
                return false;
 
80
 
 
81
        /* Can't contain any invalid characters */
 
82
        /* Test string here should match op_chars in scan.l */
 
83
        if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
 
84
                return false;
 
85
 
 
86
        /* Can't contain slash-star or dash-dash (comment starts) */
 
87
        if (strstr(name, "/*") || strstr(name, "--"))
 
88
                return false;
 
89
 
 
90
        /*
 
91
         * For SQL92 compatibility, '+' and '-' cannot be the last char of a
 
92
         * multi-char operator unless the operator contains chars that are not
 
93
         * in SQL92 operators. The idea is to lex '=-' as two operators, but
 
94
         * not to forbid operator names like '?-' that could not be sequences
 
95
         * of SQL92 operators.
 
96
         */
 
97
        if (len > 1 &&
 
98
                (name[len - 1] == '+' ||
 
99
                 name[len - 1] == '-'))
 
100
        {
 
101
                int                     ic;
 
102
 
 
103
                for (ic = len - 2; ic >= 0; ic--)
 
104
                {
 
105
                        if (strchr("~!@#^&|`?%", name[ic]))
 
106
                                break;
 
107
                }
 
108
                if (ic < 0)
 
109
                        return false;           /* nope, not valid */
 
110
        }
 
111
 
 
112
        /* != isn't valid either, because parser will convert it to <> */
 
113
        if (strcmp(name, "!=") == 0)
 
114
                return false;
 
115
 
 
116
        return true;
 
117
}
 
118
 
 
119
 
 
120
/*
 
121
 * OperatorGet
 
122
 *
 
123
 *              finds an operator given an exact specification (name, namespace,
 
124
 *              left and right type IDs).
 
125
 *
 
126
 *              *defined is set TRUE if defined (not a shell)
 
127
 */
 
128
static Oid
 
129
OperatorGet(const char *operatorName,
 
130
                        Oid operatorNamespace,
 
131
                        Oid leftObjectId,
 
132
                        Oid rightObjectId,
 
133
                        bool *defined)
 
134
{
 
135
        HeapTuple       tup;
 
136
        Oid                     operatorObjectId;
 
137
 
 
138
        tup = SearchSysCache(OPERNAMENSP,
 
139
                                                 PointerGetDatum(operatorName),
 
140
                                                 ObjectIdGetDatum(leftObjectId),
 
141
                                                 ObjectIdGetDatum(rightObjectId),
 
142
                                                 ObjectIdGetDatum(operatorNamespace));
 
143
        if (HeapTupleIsValid(tup))
 
144
        {
 
145
                RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
 
146
 
 
147
                operatorObjectId = HeapTupleGetOid(tup);
 
148
                *defined = RegProcedureIsValid(oprcode);
 
149
                ReleaseSysCache(tup);
 
150
        }
 
151
        else
 
152
        {
 
153
                operatorObjectId = InvalidOid;
 
154
                *defined = false;
 
155
        }
 
156
 
 
157
        return operatorObjectId;
 
158
}
 
159
 
 
160
/*
 
161
 * OperatorLookup
 
162
 *
 
163
 *              looks up an operator given a possibly-qualified name and
 
164
 *              left and right type IDs.
 
165
 *
 
166
 *              *defined is set TRUE if defined (not a shell)
 
167
 */
 
168
static Oid
 
169
OperatorLookup(List *operatorName,
 
170
                           Oid leftObjectId,
 
171
                           Oid rightObjectId,
 
172
                           bool *defined)
 
173
{
 
174
        Oid                     operatorObjectId;
 
175
        RegProcedure oprcode;
 
176
 
 
177
        operatorObjectId = LookupOperName(operatorName, leftObjectId,
 
178
                                                                          rightObjectId, true);
 
179
        if (!OidIsValid(operatorObjectId))
 
180
        {
 
181
                *defined = false;
 
182
                return InvalidOid;
 
183
        }
 
184
 
 
185
        oprcode = get_opcode(operatorObjectId);
 
186
        *defined = RegProcedureIsValid(oprcode);
 
187
 
 
188
        return operatorObjectId;
 
189
}
 
190
 
 
191
 
 
192
/*
 
193
 * OperatorShellMake
 
194
 *              Make a "shell" entry for a not-yet-existing operator.
 
195
 */
 
196
static Oid
 
197
OperatorShellMake(const char *operatorName,
 
198
                                  Oid operatorNamespace,
 
199
                                  Oid leftTypeId,
 
200
                                  Oid rightTypeId)
 
201
{
 
202
        Relation        pg_operator_desc;
 
203
        Oid                     operatorObjectId;
 
204
        int                     i;
 
205
        HeapTuple       tup;
 
206
        Datum           values[Natts_pg_operator];
 
207
        char            nulls[Natts_pg_operator];
 
208
        NameData        oname;
 
209
        TupleDesc       tupDesc;
 
210
 
 
211
        /*
 
212
         * validate operator name
 
213
         */
 
214
        if (!validOperatorName(operatorName))
 
215
                ereport(ERROR,
 
216
                                (errcode(ERRCODE_INVALID_NAME),
 
217
                                 errmsg("\"%s\" is not a valid operator name",
 
218
                                                operatorName)));
 
219
 
 
220
        /*
 
221
         * initialize our *nulls and *values arrays
 
222
         */
 
223
        for (i = 0; i < Natts_pg_operator; ++i)
 
224
        {
 
225
                nulls[i] = ' ';
 
226
                values[i] = (Datum) NULL;               /* redundant, but safe */
 
227
        }
 
228
 
 
229
        /*
 
230
         * initialize values[] with the operator name and input data types.
 
231
         * Note that oprcode is set to InvalidOid, indicating it's a shell.
 
232
         */
 
233
        i = 0;
 
234
        namestrcpy(&oname, operatorName);
 
235
        values[i++] = NameGetDatum(&oname); /* oprname */
 
236
        values[i++] = ObjectIdGetDatum(operatorNamespace);      /* oprnamespace */
 
237
        values[i++] = Int32GetDatum(GetUserId());       /* oprowner */
 
238
        values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');       /* oprkind */
 
239
        values[i++] = BoolGetDatum(false);      /* oprcanhash */
 
240
        values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
 
241
        values[i++] = ObjectIdGetDatum(rightTypeId);            /* oprright */
 
242
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprresult */
 
243
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcom */
 
244
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprnegate */
 
245
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprlsortop */
 
246
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrsortop */
 
247
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprltcmpop */
 
248
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprgtcmpop */
 
249
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprcode */
 
250
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprrest */
 
251
        values[i++] = ObjectIdGetDatum(InvalidOid); /* oprjoin */
 
252
 
 
253
        /*
 
254
         * open pg_operator
 
255
         */
 
256
        pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
257
        tupDesc = pg_operator_desc->rd_att;
 
258
 
 
259
        /*
 
260
         * create a new operator tuple
 
261
         */
 
262
        tup = heap_formtuple(tupDesc, values, nulls);
 
263
 
 
264
        /*
 
265
         * insert our "shell" operator tuple
 
266
         */
 
267
        operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
 
268
 
 
269
        CatalogUpdateIndexes(pg_operator_desc, tup);
 
270
 
 
271
        /* Add dependencies for the entry */
 
272
        makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));
 
273
 
 
274
        heap_freetuple(tup);
 
275
 
 
276
        /*
 
277
         * close the operator relation and return the oid.
 
278
         */
 
279
        heap_close(pg_operator_desc, RowExclusiveLock);
 
280
 
 
281
        return operatorObjectId;
 
282
}
 
283
 
 
284
/*
 
285
 * OperatorCreate
 
286
 *
 
287
 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
 
288
 *              operatorName                    name for new operator
 
289
 *              operatorNamespace               namespace for new operator
 
290
 *              leftTypeId                              X left type ID
 
291
 *              rightTypeId                             X right type ID
 
292
 *              procedureName                   procedure for operator
 
293
 *              commutatorName                  X commutator operator
 
294
 *              negatorName                             X negator operator
 
295
 *              restrictionName                 X restriction sel. procedure
 
296
 *              joinName                                X join sel. procedure
 
297
 *              canHash                                 hash join can be used with this operator
 
298
 *              leftSortName                    X left sort operator (for merge join)
 
299
 *              rightSortName                   X right sort operator (for merge join)
 
300
 *              ltCompareName                   X L<R compare operator (for merge join)
 
301
 *              gtCompareName                   X L>R compare operator (for merge join)
 
302
 *
 
303
 * This routine gets complicated because it allows the user to
 
304
 * specify operators that do not exist.  For example, if operator
 
305
 * "op" is being defined, the negator operator "negop" and the
 
306
 * commutator "commop" can also be defined without specifying
 
307
 * any information other than their names.      Since in order to
 
308
 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
 
309
 * operators must be placed in the fields of "op", a forward
 
310
 * declaration is done on the commutator and negator operators.
 
311
 * This is called creating a shell, and its main effect is to
 
312
 * create a tuple in the PG_OPERATOR catalog with minimal
 
313
 * information about the operator (just its name and types).
 
314
 * Forward declaration is used only for this purpose, it is
 
315
 * not available to the user as it is for type definition.
 
316
 *
 
317
 * Algorithm:
 
318
 *
 
319
 * check if operator already defined
 
320
 *        if so, but oprcode is null, save the Oid -- we are filling in a shell
 
321
 *        otherwise error
 
322
 * get the attribute types from relation descriptor for pg_operator
 
323
 * assign values to the fields of the operator:
 
324
 *       operatorName
 
325
 *       owner id (simply the user id of the caller)
 
326
 *       operator "kind" either "b" for binary or "l" for left unary
 
327
 *       canHash boolean
 
328
 *       leftTypeObjectId -- type must already be defined
 
329
 *       rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified
 
330
 *       resultType -- defer this, since it must be determined from
 
331
 *                                 the pg_procedure catalog
 
332
 *       commutatorObjectId -- if this is NULL, enter ObjectId=0
 
333
 *                                        else if this already exists, enter its ObjectId
 
334
 *                                        else if this does not yet exist, and is not
 
335
 *                                              the same as the main operatorName, then create
 
336
 *                                              a shell and enter the new ObjectId
 
337
 *                                        else if this does not exist but IS the same
 
338
 *                                              name & types as the main operator, set the ObjectId=0.
 
339
 *                                              (We are creating a self-commutating operator.)
 
340
 *                                              The link will be fixed later by OperatorUpd.
 
341
 *       negatorObjectId   -- same as for commutatorObjectId
 
342
 *       leftSortObjectId  -- same as for commutatorObjectId
 
343
 *       rightSortObjectId -- same as for commutatorObjectId
 
344
 *       operatorProcedure -- must access the pg_procedure catalog to get the
 
345
 *                                 ObjectId of the procedure that actually does the operator
 
346
 *                                 actions this is required.  Do a lookup to find out the
 
347
 *                                 return type of the procedure
 
348
 *       restrictionProcedure -- must access the pg_procedure catalog to get
 
349
 *                                 the ObjectId but this is optional
 
350
 *       joinProcedure -- same as restrictionProcedure
 
351
 * now either insert or replace the operator into the pg_operator catalog
 
352
 * if the operator shell is being filled in
 
353
 *       access the catalog in order to get a valid buffer
 
354
 *       create a tuple using ModifyHeapTuple
 
355
 *       get the t_self from the modified tuple and call RelationReplaceHeapTuple
 
356
 * else if a new operator is being created
 
357
 *       create a tuple using heap_formtuple
 
358
 *       call simple_heap_insert
 
359
 */
 
360
void
 
361
OperatorCreate(const char *operatorName,
 
362
                           Oid operatorNamespace,
 
363
                           Oid leftTypeId,
 
364
                           Oid rightTypeId,
 
365
                           List *procedureName,
 
366
                           List *commutatorName,
 
367
                           List *negatorName,
 
368
                           List *restrictionName,
 
369
                           List *joinName,
 
370
                           bool canHash,
 
371
                           List *leftSortName,
 
372
                           List *rightSortName,
 
373
                           List *ltCompareName,
 
374
                           List *gtCompareName)
 
375
{
 
376
        Relation        pg_operator_desc;
 
377
        HeapTuple       tup;
 
378
        char            nulls[Natts_pg_operator];
 
379
        char            replaces[Natts_pg_operator];
 
380
        Datum           values[Natts_pg_operator];
 
381
        Oid                     operatorObjectId;
 
382
        bool            operatorAlreadyDefined;
 
383
        Oid                     procOid;
 
384
        Oid                     operResultType;
 
385
        Oid                     commutatorId,
 
386
                                negatorId,
 
387
                                leftSortId,
 
388
                                rightSortId,
 
389
                                ltCompareId,
 
390
                                gtCompareId,
 
391
                                restOid,
 
392
                                joinOid;
 
393
        bool            selfCommutator = false;
 
394
        Oid                     typeId[FUNC_MAX_ARGS];
 
395
        int                     nargs;
 
396
        NameData        oname;
 
397
        TupleDesc       tupDesc;
 
398
        int                     i;
 
399
 
 
400
        /*
 
401
         * Sanity checks
 
402
         */
 
403
        if (!validOperatorName(operatorName))
 
404
                ereport(ERROR,
 
405
                                (errcode(ERRCODE_INVALID_NAME),
 
406
                                 errmsg("\"%s\" is not a valid operator name",
 
407
                                                operatorName)));
 
408
 
 
409
        if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
 
410
                ereport(ERROR,
 
411
                                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
412
                errmsg("at least one of leftarg or rightarg must be specified")));
 
413
 
 
414
        if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
 
415
        {
 
416
                /* If it's not a binary op, these things mustn't be set: */
 
417
                if (commutatorName)
 
418
                        ereport(ERROR,
 
419
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
420
                                  errmsg("only binary operators can have commutators")));
 
421
                if (joinName)
 
422
                        ereport(ERROR,
 
423
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
424
                         errmsg("only binary operators can have join selectivity")));
 
425
                if (canHash)
 
426
                        ereport(ERROR,
 
427
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
428
                                         errmsg("only binary operators can hash")));
 
429
                if (leftSortName || rightSortName || ltCompareName || gtCompareName)
 
430
                        ereport(ERROR,
 
431
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
432
                                         errmsg("only binary operators can merge join")));
 
433
        }
 
434
 
 
435
        operatorObjectId = OperatorGet(operatorName,
 
436
                                                                   operatorNamespace,
 
437
                                                                   leftTypeId,
 
438
                                                                   rightTypeId,
 
439
                                                                   &operatorAlreadyDefined);
 
440
 
 
441
        if (operatorAlreadyDefined)
 
442
                ereport(ERROR,
 
443
                                (errcode(ERRCODE_DUPLICATE_FUNCTION),
 
444
                                 errmsg("operator %s already exists",
 
445
                                                operatorName)));
 
446
 
 
447
        /*
 
448
         * At this point, if operatorObjectId is not InvalidOid then we are
 
449
         * filling in a previously-created shell.
 
450
         */
 
451
 
 
452
        /*
 
453
         * Look up registered procedures -- find the return type of
 
454
         * procedureName to place in "result" field. Do this before shells are
 
455
         * created so we don't have to worry about deleting them later.
 
456
         */
 
457
        MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
458
        if (!OidIsValid(leftTypeId))
 
459
        {
 
460
                typeId[0] = rightTypeId;
 
461
                nargs = 1;
 
462
        }
 
463
        else if (!OidIsValid(rightTypeId))
 
464
        {
 
465
                typeId[0] = leftTypeId;
 
466
                nargs = 1;
 
467
        }
 
468
        else
 
469
        {
 
470
                typeId[0] = leftTypeId;
 
471
                typeId[1] = rightTypeId;
 
472
                nargs = 2;
 
473
        }
 
474
        procOid = LookupFuncName(procedureName, nargs, typeId, false);
 
475
        operResultType = get_func_rettype(procOid);
 
476
 
 
477
        /*
 
478
         * find restriction estimator
 
479
         */
 
480
        if (restrictionName)
 
481
        {
 
482
                MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
483
                typeId[0] = INTERNALOID;        /* Query */
 
484
                typeId[1] = OIDOID;             /* operator OID */
 
485
                typeId[2] = INTERNALOID;        /* args list */
 
486
                typeId[3] = INT4OID;    /* varRelid */
 
487
 
 
488
                restOid = LookupFuncName(restrictionName, 4, typeId, false);
 
489
        }
 
490
        else
 
491
                restOid = InvalidOid;
 
492
 
 
493
        /*
 
494
         * find join estimator
 
495
         */
 
496
        if (joinName)
 
497
        {
 
498
                MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
 
499
                typeId[0] = INTERNALOID;        /* Query */
 
500
                typeId[1] = OIDOID;             /* operator OID */
 
501
                typeId[2] = INTERNALOID;        /* args list */
 
502
                typeId[3] = INT2OID;    /* jointype */
 
503
 
 
504
                joinOid = LookupFuncName(joinName, 4, typeId, false);
 
505
        }
 
506
        else
 
507
                joinOid = InvalidOid;
 
508
 
 
509
        /*
 
510
         * set up values in the operator tuple
 
511
         */
 
512
 
 
513
        for (i = 0; i < Natts_pg_operator; ++i)
 
514
        {
 
515
                values[i] = (Datum) NULL;
 
516
                replaces[i] = 'r';
 
517
                nulls[i] = ' ';
 
518
        }
 
519
 
 
520
        i = 0;
 
521
        namestrcpy(&oname, operatorName);
 
522
        values[i++] = NameGetDatum(&oname); /* oprname */
 
523
        values[i++] = ObjectIdGetDatum(operatorNamespace);      /* oprnamespace */
 
524
        values[i++] = Int32GetDatum(GetUserId());       /* oprowner */
 
525
        values[i++] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');       /* oprkind */
 
526
        values[i++] = BoolGetDatum(canHash);            /* oprcanhash */
 
527
        values[i++] = ObjectIdGetDatum(leftTypeId); /* oprleft */
 
528
        values[i++] = ObjectIdGetDatum(rightTypeId);            /* oprright */
 
529
        values[i++] = ObjectIdGetDatum(operResultType);         /* oprresult */
 
530
 
 
531
        /*
 
532
         * Set up the other operators.  If they do not currently exist, create
 
533
         * shells in order to get ObjectId's.
 
534
         */
 
535
 
 
536
        if (commutatorName)
 
537
        {
 
538
                /* commutator has reversed arg types */
 
539
                commutatorId = get_other_operator(commutatorName,
 
540
                                                                                  rightTypeId, leftTypeId,
 
541
                                                                                  operatorName, operatorNamespace,
 
542
                                                                                  leftTypeId, rightTypeId,
 
543
                                                                                  true);
 
544
 
 
545
                /*
 
546
                 * self-linkage to this operator; will fix below. Note that only
 
547
                 * self-linkage for commutation makes sense.
 
548
                 */
 
549
                if (!OidIsValid(commutatorId))
 
550
                        selfCommutator = true;
 
551
        }
 
552
        else
 
553
                commutatorId = InvalidOid;
 
554
        values[i++] = ObjectIdGetDatum(commutatorId);           /* oprcom */
 
555
 
 
556
        if (negatorName)
 
557
        {
 
558
                /* negator has same arg types */
 
559
                negatorId = get_other_operator(negatorName,
 
560
                                                                           leftTypeId, rightTypeId,
 
561
                                                                           operatorName, operatorNamespace,
 
562
                                                                           leftTypeId, rightTypeId,
 
563
                                                                           false);
 
564
        }
 
565
        else
 
566
                negatorId = InvalidOid;
 
567
        values[i++] = ObjectIdGetDatum(negatorId);      /* oprnegate */
 
568
 
 
569
        if (leftSortName)
 
570
        {
 
571
                /* left sort op takes left-side data type */
 
572
                leftSortId = get_other_operator(leftSortName,
 
573
                                                                                leftTypeId, leftTypeId,
 
574
                                                                                operatorName, operatorNamespace,
 
575
                                                                                leftTypeId, rightTypeId,
 
576
                                                                                false);
 
577
        }
 
578
        else
 
579
                leftSortId = InvalidOid;
 
580
        values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
 
581
 
 
582
        if (rightSortName)
 
583
        {
 
584
                /* right sort op takes right-side data type */
 
585
                rightSortId = get_other_operator(rightSortName,
 
586
                                                                                 rightTypeId, rightTypeId,
 
587
                                                                                 operatorName, operatorNamespace,
 
588
                                                                                 leftTypeId, rightTypeId,
 
589
                                                                                 false);
 
590
        }
 
591
        else
 
592
                rightSortId = InvalidOid;
 
593
        values[i++] = ObjectIdGetDatum(rightSortId);            /* oprrsortop */
 
594
 
 
595
        if (ltCompareName)
 
596
        {
 
597
                /* comparator has same arg types */
 
598
                ltCompareId = get_other_operator(ltCompareName,
 
599
                                                                                 leftTypeId, rightTypeId,
 
600
                                                                                 operatorName, operatorNamespace,
 
601
                                                                                 leftTypeId, rightTypeId,
 
602
                                                                                 false);
 
603
        }
 
604
        else
 
605
                ltCompareId = InvalidOid;
 
606
        values[i++] = ObjectIdGetDatum(ltCompareId);            /* oprltcmpop */
 
607
 
 
608
        if (gtCompareName)
 
609
        {
 
610
                /* comparator has same arg types */
 
611
                gtCompareId = get_other_operator(gtCompareName,
 
612
                                                                                 leftTypeId, rightTypeId,
 
613
                                                                                 operatorName, operatorNamespace,
 
614
                                                                                 leftTypeId, rightTypeId,
 
615
                                                                                 false);
 
616
        }
 
617
        else
 
618
                gtCompareId = InvalidOid;
 
619
        values[i++] = ObjectIdGetDatum(gtCompareId);            /* oprgtcmpop */
 
620
 
 
621
        values[i++] = ObjectIdGetDatum(procOid);        /* oprcode */
 
622
        values[i++] = ObjectIdGetDatum(restOid);        /* oprrest */
 
623
        values[i++] = ObjectIdGetDatum(joinOid);        /* oprjoin */
 
624
 
 
625
        pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
626
 
 
627
        /*
 
628
         * If we are adding to an operator shell, update; else insert
 
629
         */
 
630
        if (operatorObjectId)
 
631
        {
 
632
                tup = SearchSysCacheCopy(OPEROID,
 
633
                                                                 ObjectIdGetDatum(operatorObjectId),
 
634
                                                                 0, 0, 0);
 
635
                if (!HeapTupleIsValid(tup))
 
636
                        elog(ERROR, "cache lookup failed for operator %u",
 
637
                                 operatorObjectId);
 
638
 
 
639
                tup = heap_modifytuple(tup,
 
640
                                                           pg_operator_desc,
 
641
                                                           values,
 
642
                                                           nulls,
 
643
                                                           replaces);
 
644
 
 
645
                simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
646
        }
 
647
        else
 
648
        {
 
649
                tupDesc = pg_operator_desc->rd_att;
 
650
                tup = heap_formtuple(tupDesc, values, nulls);
 
651
 
 
652
                operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
 
653
        }
 
654
 
 
655
        /* Must update the indexes in either case */
 
656
        CatalogUpdateIndexes(pg_operator_desc, tup);
 
657
 
 
658
        /* Add dependencies for the entry */
 
659
        makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));
 
660
 
 
661
        heap_close(pg_operator_desc, RowExclusiveLock);
 
662
 
 
663
        /*
 
664
         * If a commutator and/or negator link is provided, update the other
 
665
         * operator(s) to point at this one, if they don't already have a
 
666
         * link. This supports an alternate style of operator definition
 
667
         * wherein the user first defines one operator without giving negator
 
668
         * or commutator, then defines the other operator of the pair with the
 
669
         * proper commutator or negator attribute.      That style doesn't require
 
670
         * creation of a shell, and it's the only style that worked right
 
671
         * before Postgres version 6.5. This code also takes care of the
 
672
         * situation where the new operator is its own commutator.
 
673
         */
 
674
        if (selfCommutator)
 
675
                commutatorId = operatorObjectId;
 
676
 
 
677
        if (OidIsValid(commutatorId) || OidIsValid(negatorId))
 
678
                OperatorUpd(operatorObjectId, commutatorId, negatorId);
 
679
}
 
680
 
 
681
/*
 
682
 * Try to lookup another operator (commutator, etc)
 
683
 *
 
684
 * If not found, check to see if it is exactly the operator we are trying
 
685
 * to define; if so, return InvalidOid.  (Note that this case is only
 
686
 * sensible for a commutator, so we error out otherwise.)  If it is not
 
687
 * the same operator, create a shell operator.
 
688
 */
 
689
static Oid
 
690
get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
 
691
                                   const char *operatorName, Oid operatorNamespace,
 
692
                                   Oid leftTypeId, Oid rightTypeId, bool isCommutator)
 
693
{
 
694
        Oid                     other_oid;
 
695
        bool            otherDefined;
 
696
        char       *otherName;
 
697
        Oid                     otherNamespace;
 
698
        AclResult       aclresult;
 
699
 
 
700
        other_oid = OperatorLookup(otherOp,
 
701
                                                           otherLeftTypeId,
 
702
                                                           otherRightTypeId,
 
703
                                                           &otherDefined);
 
704
 
 
705
        if (OidIsValid(other_oid))
 
706
        {
 
707
                /* other op already in catalogs */
 
708
                return other_oid;
 
709
        }
 
710
 
 
711
        otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
 
712
                                                                                                           &otherName);
 
713
 
 
714
        if (strcmp(otherName, operatorName) == 0 &&
 
715
                otherNamespace == operatorNamespace &&
 
716
                otherLeftTypeId == leftTypeId &&
 
717
                otherRightTypeId == rightTypeId)
 
718
        {
 
719
                /*
 
720
                 * self-linkage to this operator; caller will fix later. Note that
 
721
                 * only self-linkage for commutation makes sense.
 
722
                 */
 
723
                if (!isCommutator)
 
724
                        ereport(ERROR,
 
725
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
 
726
                                         errmsg("operator cannot be its own negator or sort operator")));
 
727
                return InvalidOid;
 
728
        }
 
729
 
 
730
        /* not in catalogs, different from operator, so make shell */
 
731
 
 
732
        aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
 
733
                                                                          ACL_CREATE);
 
734
        if (aclresult != ACLCHECK_OK)
 
735
                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 
736
                                           get_namespace_name(otherNamespace));
 
737
 
 
738
        other_oid = OperatorShellMake(otherName,
 
739
                                                                  otherNamespace,
 
740
                                                                  otherLeftTypeId,
 
741
                                                                  otherRightTypeId);
 
742
        return other_oid;
 
743
}
 
744
 
 
745
/*
 
746
 * OperatorUpd
 
747
 *
 
748
 *      For a given operator, look up its negator and commutator operators.
 
749
 *      If they are defined, but their negator and commutator fields
 
750
 *      (respectively) are empty, then use the new operator for neg or comm.
 
751
 *      This solves a problem for users who need to insert two new operators
 
752
 *      which are the negator or commutator of each other.
 
753
 */
 
754
static void
 
755
OperatorUpd(Oid baseId, Oid commId, Oid negId)
 
756
{
 
757
        int                     i;
 
758
        Relation        pg_operator_desc;
 
759
        HeapTuple       tup;
 
760
        char            nulls[Natts_pg_operator];
 
761
        char            replaces[Natts_pg_operator];
 
762
        Datum           values[Natts_pg_operator];
 
763
 
 
764
        for (i = 0; i < Natts_pg_operator; ++i)
 
765
        {
 
766
                values[i] = (Datum) 0;
 
767
                replaces[i] = ' ';
 
768
                nulls[i] = ' ';
 
769
        }
 
770
 
 
771
        /*
 
772
         * check and update the commutator & negator, if necessary
 
773
         *
 
774
         * First make sure we can see them...
 
775
         */
 
776
        CommandCounterIncrement();
 
777
 
 
778
        pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
 
779
 
 
780
        tup = SearchSysCacheCopy(OPEROID,
 
781
                                                         ObjectIdGetDatum(commId),
 
782
                                                         0, 0, 0);
 
783
 
 
784
        /*
 
785
         * if the commutator and negator are the same operator, do one update.
 
786
         * XXX this is probably useless code --- I doubt it ever makes sense
 
787
         * for commutator and negator to be the same thing...
 
788
         */
 
789
        if (commId == negId)
 
790
        {
 
791
                if (HeapTupleIsValid(tup))
 
792
                {
 
793
                        Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
 
794
 
 
795
                        if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
 
796
                        {
 
797
                                if (!OidIsValid(t->oprnegate))
 
798
                                {
 
799
                                        values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
 
800
                                        replaces[Anum_pg_operator_oprnegate - 1] = 'r';
 
801
                                }
 
802
 
 
803
                                if (!OidIsValid(t->oprcom))
 
804
                                {
 
805
                                        values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
 
806
                                        replaces[Anum_pg_operator_oprcom - 1] = 'r';
 
807
                                }
 
808
 
 
809
                                tup = heap_modifytuple(tup,
 
810
                                                                           pg_operator_desc,
 
811
                                                                           values,
 
812
                                                                           nulls,
 
813
                                                                           replaces);
 
814
 
 
815
                                simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
816
 
 
817
                                CatalogUpdateIndexes(pg_operator_desc, tup);
 
818
                        }
 
819
                }
 
820
 
 
821
                heap_close(pg_operator_desc, RowExclusiveLock);
 
822
 
 
823
                return;
 
824
        }
 
825
 
 
826
        /* if commutator and negator are different, do two updates */
 
827
 
 
828
        if (HeapTupleIsValid(tup) &&
 
829
                !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
 
830
        {
 
831
                values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
 
832
                replaces[Anum_pg_operator_oprcom - 1] = 'r';
 
833
 
 
834
                tup = heap_modifytuple(tup,
 
835
                                                           pg_operator_desc,
 
836
                                                           values,
 
837
                                                           nulls,
 
838
                                                           replaces);
 
839
 
 
840
                simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
841
 
 
842
                CatalogUpdateIndexes(pg_operator_desc, tup);
 
843
 
 
844
                values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
 
845
                replaces[Anum_pg_operator_oprcom - 1] = ' ';
 
846
        }
 
847
 
 
848
        /* check and update the negator, if necessary */
 
849
 
 
850
        tup = SearchSysCacheCopy(OPEROID,
 
851
                                                         ObjectIdGetDatum(negId),
 
852
                                                         0, 0, 0);
 
853
 
 
854
        if (HeapTupleIsValid(tup) &&
 
855
                !(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
 
856
        {
 
857
                values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
 
858
                replaces[Anum_pg_operator_oprnegate - 1] = 'r';
 
859
 
 
860
                tup = heap_modifytuple(tup,
 
861
                                                           pg_operator_desc,
 
862
                                                           values,
 
863
                                                           nulls,
 
864
                                                           replaces);
 
865
 
 
866
                simple_heap_update(pg_operator_desc, &tup->t_self, tup);
 
867
 
 
868
                CatalogUpdateIndexes(pg_operator_desc, tup);
 
869
        }
 
870
 
 
871
        heap_close(pg_operator_desc, RowExclusiveLock);
 
872
}
 
873
 
 
874
/*
 
875
 * Create dependencies for a new operator (either a freshly inserted
 
876
 * complete operator, a new shell operator, or a just-updated shell).
 
877
 *
 
878
 * NB: the OidIsValid tests in this routine are necessary, in case
 
879
 * the given operator is a shell.
 
880
 */
 
881
static void
 
882
makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid)
 
883
{
 
884
        Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
 
885
        ObjectAddress myself,
 
886
                                referenced;
 
887
 
 
888
        myself.classId = pg_operator_relid;
 
889
        myself.objectId = HeapTupleGetOid(tuple);
 
890
        myself.objectSubId = 0;
 
891
 
 
892
        /* In case we are updating a shell, delete any existing entries */
 
893
        deleteDependencyRecordsFor(myself.classId, myself.objectId);
 
894
 
 
895
        /* Dependency on namespace */
 
896
        if (OidIsValid(oper->oprnamespace))
 
897
        {
 
898
                referenced.classId = get_system_catalog_relid(NamespaceRelationName);
 
899
                referenced.objectId = oper->oprnamespace;
 
900
                referenced.objectSubId = 0;
 
901
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
902
        }
 
903
 
 
904
        /* Dependency on left type */
 
905
        if (OidIsValid(oper->oprleft))
 
906
        {
 
907
                referenced.classId = RelOid_pg_type;
 
908
                referenced.objectId = oper->oprleft;
 
909
                referenced.objectSubId = 0;
 
910
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
911
        }
 
912
 
 
913
        /* Dependency on right type */
 
914
        if (OidIsValid(oper->oprright))
 
915
        {
 
916
                referenced.classId = RelOid_pg_type;
 
917
                referenced.objectId = oper->oprright;
 
918
                referenced.objectSubId = 0;
 
919
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
920
        }
 
921
 
 
922
        /* Dependency on result type */
 
923
        if (OidIsValid(oper->oprresult))
 
924
        {
 
925
                referenced.classId = RelOid_pg_type;
 
926
                referenced.objectId = oper->oprresult;
 
927
                referenced.objectSubId = 0;
 
928
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
929
        }
 
930
 
 
931
        /*
 
932
         * NOTE: we do not consider the operator to depend on the associated
 
933
         * operators oprcom, oprnegate, oprlsortop, oprrsortop, oprltcmpop,
 
934
         * oprgtcmpop.  We would not want to delete this operator if those go
 
935
         * away, but only reset the link fields; which is not a function that
 
936
         * the dependency code can presently handle.  (Something could perhaps
 
937
         * be done with objectSubId though.)  For now, it's okay to let those
 
938
         * links dangle if a referenced operator is removed.
 
939
         */
 
940
 
 
941
        /* Dependency on implementation function */
 
942
        if (OidIsValid(oper->oprcode))
 
943
        {
 
944
                referenced.classId = RelOid_pg_proc;
 
945
                referenced.objectId = oper->oprcode;
 
946
                referenced.objectSubId = 0;
 
947
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
948
        }
 
949
 
 
950
        /* Dependency on restriction selectivity function */
 
951
        if (OidIsValid(oper->oprrest))
 
952
        {
 
953
                referenced.classId = RelOid_pg_proc;
 
954
                referenced.objectId = oper->oprrest;
 
955
                referenced.objectSubId = 0;
 
956
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
957
        }
 
958
 
 
959
        /* Dependency on join selectivity function */
 
960
        if (OidIsValid(oper->oprjoin))
 
961
        {
 
962
                referenced.classId = RelOid_pg_proc;
 
963
                referenced.objectId = oper->oprjoin;
 
964
                referenced.objectSubId = 0;
 
965
                recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
966
        }
 
967
}