YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/postgres/src/backend/catalog/pg_operator.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * pg_operator.c
4
 *    routines to support manipulation of the pg_operator relation
5
 *
6
 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/catalog/pg_operator.c
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 "access/htup_details.h"
22
#include "access/xact.h"
23
#include "catalog/dependency.h"
24
#include "catalog/indexing.h"
25
#include "catalog/namespace.h"
26
#include "catalog/objectaccess.h"
27
#include "catalog/pg_namespace.h"
28
#include "catalog/pg_operator.h"
29
#include "catalog/pg_proc.h"
30
#include "catalog/pg_type.h"
31
#include "miscadmin.h"
32
#include "parser/parse_oper.h"
33
#include "utils/acl.h"
34
#include "utils/builtins.h"
35
#include "utils/lsyscache.h"
36
#include "utils/rel.h"
37
#include "utils/syscache.h"
38
39
40
static Oid OperatorGet(const char *operatorName,
41
      Oid operatorNamespace,
42
      Oid leftObjectId,
43
      Oid rightObjectId,
44
      bool *defined);
45
46
static Oid OperatorLookup(List *operatorName,
47
         Oid leftObjectId,
48
         Oid rightObjectId,
49
         bool *defined);
50
51
static Oid OperatorShellMake(const char *operatorName,
52
          Oid operatorNamespace,
53
          Oid leftTypeId,
54
          Oid rightTypeId);
55
56
static Oid get_other_operator(List *otherOp,
57
           Oid otherLeftTypeId, Oid otherRightTypeId,
58
           const char *operatorName, Oid operatorNamespace,
59
           Oid leftTypeId, Oid rightTypeId,
60
           bool isCommutator);
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
461
{
75
461
  size_t    len = strlen(name);
76
77
  /* Can't be empty or too long */
78
461
  if (len == 0 || len >= NAMEDATALEN)
79
0
    return false;
80
81
  /* Can't contain any invalid characters */
82
  /* Test string here should match op_chars in scan.l */
83
461
  if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
84
0
    return false;
85
86
  /* Can't contain slash-star or dash-dash (comment starts) */
87
461
  if (strstr(name, "/*") || strstr(name, "--"))
88
0
    return false;
89
90
  /*
91
   * For SQL standard compatibility, '+' and '-' cannot be the last char of
92
   * a multi-char operator unless the operator contains chars that are not
93
   * in SQL operators. The idea is to lex '=-' as two operators, but not to
94
   * forbid operator names like '?-' that could not be sequences of standard
95
   * SQL operators.
96
   */
97
461
  if (len > 1 &&
98
461
    
(267
name[len - 1] == '+'267
||
99
267
     name[len - 1] == '-'))
100
1
  {
101
1
    int     ic;
102
103
2
    for (ic = len - 2; ic >= 0; 
ic--1
)
104
2
    {
105
2
      if (strchr("~!@#^&|`?%", name[ic]))
106
1
        break;
107
2
    }
108
1
    if (ic < 0)
109
0
      return false;   /* nope, not valid */
110
1
  }
111
112
  /* != isn't valid either, because parser will convert it to <> */
113
461
  if (strcmp(name, "!=") == 0)
114
0
    return false;
115
116
461
  return true;
117
461
}
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
313
{
135
313
  HeapTuple tup;
136
313
  Oid     operatorObjectId;
137
138
313
  tup = SearchSysCache4(OPERNAMENSP,
139
313
              PointerGetDatum(operatorName),
140
313
              ObjectIdGetDatum(leftObjectId),
141
313
              ObjectIdGetDatum(rightObjectId),
142
313
              ObjectIdGetDatum(operatorNamespace));
143
313
  if (HeapTupleIsValid(tup))
144
144
  {
145
144
    RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
146
147
144
    operatorObjectId = HeapTupleGetOid(tup);
148
144
    *defined = RegProcedureIsValid(oprcode);
149
144
    ReleaseSysCache(tup);
150
144
  }
151
169
  else
152
169
  {
153
169
    operatorObjectId = InvalidOid;
154
169
    *defined = false;
155
169
  }
156
157
313
  return operatorObjectId;
158
313
}
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
446
{
174
446
  Oid     operatorObjectId;
175
446
  RegProcedure oprcode;
176
177
446
  operatorObjectId = LookupOperName(NULL, operatorName,
178
446
                    leftObjectId, rightObjectId,
179
446
                    true, -1);
180
446
  if (!OidIsValid(operatorObjectId))
181
185
  {
182
185
    *defined = false;
183
185
    return InvalidOid;
184
185
  }
185
186
261
  oprcode = get_opcode(operatorObjectId);
187
261
  *defined = RegProcedureIsValid(oprcode);
188
189
261
  return operatorObjectId;
190
446
}
191
192
193
/*
194
 * OperatorShellMake
195
 *    Make a "shell" entry for a not-yet-existing operator.
196
 */
197
static Oid
198
OperatorShellMake(const char *operatorName,
199
          Oid operatorNamespace,
200
          Oid leftTypeId,
201
          Oid rightTypeId)
202
148
{
203
148
  Relation  pg_operator_desc;
204
148
  Oid     operatorObjectId;
205
148
  int     i;
206
148
  HeapTuple tup;
207
148
  Datum   values[Natts_pg_operator];
208
148
  bool    nulls[Natts_pg_operator];
209
148
  NameData  oname;
210
148
  TupleDesc tupDesc;
211
212
  /*
213
   * validate operator name
214
   */
215
148
  if (!validOperatorName(operatorName))
216
148
    ereport(ERROR,
217
148
        (errcode(ERRCODE_INVALID_NAME),
218
148
         errmsg("\"%s\" is not a valid operator name",
219
148
            operatorName)));
220
221
  /*
222
   * initialize our *nulls and *values arrays
223
   */
224
2.22k
  
for (i = 0; 148
i < Natts_pg_operator;
++i2.07k
)
225
2.07k
  {
226
2.07k
    nulls[i] = false;
227
2.07k
    values[i] = (Datum) NULL; /* redundant, but safe */
228
2.07k
  }
229
230
  /*
231
   * initialize values[] with the operator name and input data types. Note
232
   * that oprcode is set to InvalidOid, indicating it's a shell.
233
   */
234
148
  namestrcpy(&oname, operatorName);
235
148
  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
236
148
  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
237
148
  values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
238
148
  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
239
148
  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(false);
240
148
  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(false);
241
148
  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
242
148
  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
243
148
  values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(InvalidOid);
244
148
  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(InvalidOid);
245
148
  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(InvalidOid);
246
148
  values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(InvalidOid);
247
148
  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
248
148
  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(InvalidOid);
249
250
  /*
251
   * open pg_operator
252
   */
253
148
  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
254
148
  tupDesc = pg_operator_desc->rd_att;
255
256
  /*
257
   * create a new operator tuple
258
   */
259
148
  tup = heap_form_tuple(tupDesc, values, nulls);
260
261
  /*
262
   * insert our "shell" operator tuple
263
   */
264
148
  operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
265
266
  /* Add dependencies for the entry */
267
148
  makeOperatorDependencies(tup, false);
268
269
148
  heap_freetuple(tup);
270
271
  /* Post creation hook for new shell operator */
272
148
  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
273
274
  /*
275
   * Make sure the tuple is visible for subsequent lookups/updates.
276
   */
277
148
  CommandCounterIncrement();
278
279
  /*
280
   * close the operator relation and return the oid.
281
   */
282
148
  heap_close(pg_operator_desc, RowExclusiveLock);
283
284
148
  return operatorObjectId;
285
148
}
286
287
/*
288
 * OperatorCreate
289
 *
290
 * "X" indicates an optional argument (i.e. one that can be NULL or 0)
291
 *    operatorName      name for new operator
292
 *    operatorNamespace   namespace for new operator
293
 *    leftTypeId        X left type ID
294
 *    rightTypeId       X right type ID
295
 *    procedureId       procedure ID for operator
296
 *    commutatorName      X commutator operator
297
 *    negatorName       X negator operator
298
 *    restrictionId     X restriction selectivity procedure ID
299
 *    joinId          X join selectivity procedure ID
300
 *    canMerge        merge join can be used with this operator
301
 *    canHash         hash join can be used with this operator
302
 *
303
 * The caller should have validated properties and permissions for the
304
 * objects passed as OID references.  We must handle the commutator and
305
 * negator operator references specially, however, since those need not
306
 * exist beforehand.
307
 *
308
 * This routine gets complicated because it allows the user to
309
 * specify operators that do not exist.  For example, if operator
310
 * "op" is being defined, the negator operator "negop" and the
311
 * commutator "commop" can also be defined without specifying
312
 * any information other than their names.  Since in order to
313
 * add "op" to the PG_OPERATOR catalog, all the Oid's for these
314
 * operators must be placed in the fields of "op", a forward
315
 * declaration is done on the commutator and negator operators.
316
 * This is called creating a shell, and its main effect is to
317
 * create a tuple in the PG_OPERATOR catalog with minimal
318
 * information about the operator (just its name and types).
319
 * Forward declaration is used only for this purpose, it is
320
 * not available to the user as it is for type definition.
321
 */
322
ObjectAddress
323
OperatorCreate(const char *operatorName,
324
         Oid operatorNamespace,
325
         Oid leftTypeId,
326
         Oid rightTypeId,
327
         Oid procedureId,
328
         List *commutatorName,
329
         List *negatorName,
330
         Oid restrictionId,
331
         Oid joinId,
332
         bool canMerge,
333
         bool canHash)
334
313
{
335
313
  Relation  pg_operator_desc;
336
313
  HeapTuple tup;
337
313
  bool    isUpdate;
338
313
  bool    nulls[Natts_pg_operator];
339
313
  bool    replaces[Natts_pg_operator];
340
313
  Datum   values[Natts_pg_operator];
341
313
  Oid     operatorObjectId;
342
313
  bool    operatorAlreadyDefined;
343
313
  Oid     operResultType;
344
313
  Oid     commutatorId,
345
313
        negatorId;
346
313
  bool    selfCommutator = false;
347
313
  NameData  oname;
348
313
  int     i;
349
313
  ObjectAddress address;
350
351
  /*
352
   * Sanity checks
353
   */
354
313
  if (!validOperatorName(operatorName))
355
313
    ereport(ERROR,
356
313
        (errcode(ERRCODE_INVALID_NAME),
357
313
         errmsg("\"%s\" is not a valid operator name",
358
313
            operatorName)));
359
360
313
  if (!(OidIsValid(leftTypeId) && 
OidIsValid308
(rightTypeId)))
361
9
  {
362
    /* If it's not a binary op, these things mustn't be set: */
363
9
    if (commutatorName)
364
9
      ereport(ERROR,
365
9
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
366
9
           errmsg("only binary operators can have commutators")));
367
9
    if (OidIsValid(joinId))
368
9
      ereport(ERROR,
369
9
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
370
9
           errmsg("only binary operators can have join selectivity")));
371
9
    if (canMerge)
372
9
      ereport(ERROR,
373
9
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
374
9
           errmsg("only binary operators can merge join")));
375
9
    if (canHash)
376
9
      ereport(ERROR,
377
9
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
378
9
           errmsg("only binary operators can hash")));
379
9
  }
380
381
313
  operResultType = get_func_rettype(procedureId);
382
383
313
  if (operResultType != BOOLOID)
384
71
  {
385
    /* If it's not a boolean op, these things mustn't be set: */
386
71
    if (negatorName)
387
71
      ereport(ERROR,
388
71
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
389
71
           errmsg("only boolean operators can have negators")));
390
71
    if (OidIsValid(restrictionId))
391
71
      ereport(ERROR,
392
71
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
393
71
           errmsg("only boolean operators can have restriction selectivity")));
394
71
    if (OidIsValid(joinId))
395
71
      ereport(ERROR,
396
71
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
397
71
           errmsg("only boolean operators can have join selectivity")));
398
71
    if (canMerge)
399
71
      ereport(ERROR,
400
71
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
401
71
           errmsg("only boolean operators can merge join")));
402
71
    if (canHash)
403
71
      ereport(ERROR,
404
71
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
405
71
           errmsg("only boolean operators can hash")));
406
71
  }
407
408
313
  operatorObjectId = OperatorGet(operatorName,
409
313
                   operatorNamespace,
410
313
                   leftTypeId,
411
313
                   rightTypeId,
412
313
                   &operatorAlreadyDefined);
413
414
313
  if (operatorAlreadyDefined)
415
313
    ereport(ERROR,
416
313
        (errcode(ERRCODE_DUPLICATE_FUNCTION),
417
313
         errmsg("operator %s already exists",
418
313
            operatorName)));
419
420
  /*
421
   * At this point, if operatorObjectId is not InvalidOid then we are
422
   * filling in a previously-created shell.  Insist that the user own any
423
   * such shell.
424
   */
425
313
  if (OidIsValid(operatorObjectId) &&
426
313
    
!pg_oper_ownercheck(operatorObjectId, GetUserId())144
)
427
0
    aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
428
0
             operatorName);
429
430
  /*
431
   * Set up the other operators.  If they do not currently exist, create
432
   * shells in order to get ObjectId's.
433
   */
434
435
313
  if (commutatorName)
436
249
  {
437
    /* commutator has reversed arg types */
438
249
    commutatorId = get_other_operator(commutatorName,
439
249
                      rightTypeId, leftTypeId,
440
249
                      operatorName, operatorNamespace,
441
249
                      leftTypeId, rightTypeId,
442
249
                      true);
443
444
    /* Permission check: must own other operator */
445
249
    if (OidIsValid(commutatorId) &&
446
249
      
!pg_oper_ownercheck(commutatorId, GetUserId())212
)
447
0
      aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
448
0
               NameListToString(commutatorName));
449
450
    /*
451
     * self-linkage to this operator; will fix below. Note that only
452
     * self-linkage for commutation makes sense.
453
     */
454
249
    if (!OidIsValid(commutatorId))
455
37
      selfCommutator = true;
456
249
  }
457
64
  else
458
64
    commutatorId = InvalidOid;
459
460
313
  if (negatorName)
461
197
  {
462
    /* negator has same arg types */
463
197
    negatorId = get_other_operator(negatorName,
464
197
                     leftTypeId, rightTypeId,
465
197
                     operatorName, operatorNamespace,
466
197
                     leftTypeId, rightTypeId,
467
197
                     false);
468
469
    /* Permission check: must own other operator */
470
197
    if (OidIsValid(negatorId) &&
471
197
      !pg_oper_ownercheck(negatorId, GetUserId()))
472
0
      aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_OPERATOR,
473
0
               NameListToString(negatorName));
474
197
  }
475
116
  else
476
116
    negatorId = InvalidOid;
477
478
  /*
479
   * set up values in the operator tuple
480
   */
481
482
4.69k
  for (i = 0; i < Natts_pg_operator; 
++i4.38k
)
483
4.38k
  {
484
4.38k
    values[i] = (Datum) NULL;
485
4.38k
    replaces[i] = true;
486
4.38k
    nulls[i] = false;
487
4.38k
  }
488
489
313
  namestrcpy(&oname, operatorName);
490
313
  values[Anum_pg_operator_oprname - 1] = NameGetDatum(&oname);
491
313
  values[Anum_pg_operator_oprnamespace - 1] = ObjectIdGetDatum(operatorNamespace);
492
313
  values[Anum_pg_operator_oprowner - 1] = ObjectIdGetDatum(GetUserId());
493
313
  values[Anum_pg_operator_oprkind - 1] = CharGetDatum(leftTypeId ? (rightTypeId ? 'b' : 'r') : 'l');
494
313
  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
495
313
  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
496
313
  values[Anum_pg_operator_oprleft - 1] = ObjectIdGetDatum(leftTypeId);
497
313
  values[Anum_pg_operator_oprright - 1] = ObjectIdGetDatum(rightTypeId);
498
313
  values[Anum_pg_operator_oprresult - 1] = ObjectIdGetDatum(operResultType);
499
313
  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorId);
500
313
  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorId);
501
313
  values[Anum_pg_operator_oprcode - 1] = ObjectIdGetDatum(procedureId);
502
313
  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionId);
503
313
  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinId);
504
505
313
  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
506
507
  /*
508
   * If we are replacing an operator shell, update; else insert
509
   */
510
313
  if (operatorObjectId)
511
144
  {
512
144
    isUpdate = true;
513
514
144
    tup = SearchSysCacheCopy1(OPEROID,
515
144
                  ObjectIdGetDatum(operatorObjectId));
516
144
    if (!HeapTupleIsValid(tup))
517
0
      elog(ERROR, "cache lookup failed for operator %u",
518
144
         operatorObjectId);
519
520
144
    tup = heap_modify_tuple(tup,
521
144
                RelationGetDescr(pg_operator_desc),
522
144
                values,
523
144
                nulls,
524
144
                replaces);
525
526
144
    CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
527
144
  }
528
169
  else
529
169
  {
530
169
    isUpdate = false;
531
532
169
    tup = heap_form_tuple(RelationGetDescr(pg_operator_desc),
533
169
                values, nulls);
534
535
169
    operatorObjectId = CatalogTupleInsert(pg_operator_desc, tup);
536
169
  }
537
538
  /* Add dependencies for the entry */
539
313
  address = makeOperatorDependencies(tup, isUpdate);
540
541
  /* Post creation hook for new operator */
542
313
  InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
543
544
313
  heap_close(pg_operator_desc, RowExclusiveLock);
545
546
  /*
547
   * If a commutator and/or negator link is provided, update the other
548
   * operator(s) to point at this one, if they don't already have a link.
549
   * This supports an alternative style of operator definition wherein the
550
   * user first defines one operator without giving negator or commutator,
551
   * then defines the other operator of the pair with the proper commutator
552
   * or negator attribute.  That style doesn't require creation of a shell,
553
   * and it's the only style that worked right before Postgres version 6.5.
554
   * This code also takes care of the situation where the new operator is
555
   * its own commutator.
556
   */
557
313
  if (selfCommutator)
558
37
    commutatorId = operatorObjectId;
559
560
313
  if (OidIsValid(commutatorId) || 
OidIsValid64
(negatorId))
561
249
    OperatorUpd(operatorObjectId, commutatorId, negatorId, false);
562
563
313
  return address;
564
313
}
565
566
/*
567
 * Try to lookup another operator (commutator, etc)
568
 *
569
 * If not found, check to see if it is exactly the operator we are trying
570
 * to define; if so, return InvalidOid.  (Note that this case is only
571
 * sensible for a commutator, so we error out otherwise.)  If it is not
572
 * the same operator, create a shell operator.
573
 */
574
static Oid
575
get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
576
           const char *operatorName, Oid operatorNamespace,
577
           Oid leftTypeId, Oid rightTypeId, bool isCommutator)
578
446
{
579
446
  Oid     other_oid;
580
446
  bool    otherDefined;
581
446
  char     *otherName;
582
446
  Oid     otherNamespace;
583
446
  AclResult aclresult;
584
585
446
  other_oid = OperatorLookup(otherOp,
586
446
                 otherLeftTypeId,
587
446
                 otherRightTypeId,
588
446
                 &otherDefined);
589
590
446
  if (OidIsValid(other_oid))
591
261
  {
592
    /* other op already in catalogs */
593
261
    return other_oid;
594
261
  }
595
596
185
  otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
597
185
                             &otherName);
598
599
185
  if (strcmp(otherName, operatorName) == 0 &&
600
185
    
otherNamespace == operatorNamespace57
&&
601
185
    
otherLeftTypeId == leftTypeId57
&&
602
185
    
otherRightTypeId == rightTypeId37
)
603
37
  {
604
    /*
605
     * self-linkage to this operator; caller will fix later. Note that
606
     * only self-linkage for commutation makes sense.
607
     */
608
37
    if (!isCommutator)
609
37
      ereport(ERROR,
610
37
          (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
611
37
           errmsg("operator cannot be its own negator or sort operator")));
612
37
    return InvalidOid;
613
37
  }
614
615
  /* not in catalogs, different from operator, so make shell */
616
617
148
  aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
618
148
                    ACL_CREATE);
619
148
  if (aclresult != ACLCHECK_OK)
620
0
    aclcheck_error(aclresult, OBJECT_SCHEMA,
621
0
             get_namespace_name(otherNamespace));
622
623
148
  other_oid = OperatorShellMake(otherName,
624
148
                  otherNamespace,
625
148
                  otherLeftTypeId,
626
148
                  otherRightTypeId);
627
148
  return other_oid;
628
185
}
629
630
/*
631
 * OperatorUpd
632
 *
633
 *  For a given operator, look up its negator and commutator operators.
634
 *  When isDelete is false, update their negator and commutator fields to
635
 *  point back to the given operator; when isDelete is true, update those
636
 *  fields to no longer point back to the given operator.
637
 *
638
 *  The !isDelete case solves a problem for users who need to insert two new
639
 *  operators that are the negator or commutator of each other, while the
640
 *  isDelete case is needed so as not to leave dangling OID links behind
641
 *  after dropping an operator.
642
 */
643
void
644
OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
645
420
{
646
420
  Relation  pg_operator_desc;
647
420
  HeapTuple tup;
648
649
  /*
650
   * If we're making an operator into its own commutator, then we need a
651
   * command-counter increment here, since we've just inserted the tuple
652
   * we're about to update.  But when we're dropping an operator, we can
653
   * skip this because we're at the beginning of the command.
654
   */
655
420
  if (!isDelete)
656
249
    CommandCounterIncrement();
657
658
  /* Open the relation. */
659
420
  pg_operator_desc = heap_open(OperatorRelationId, RowExclusiveLock);
660
661
  /* Get a writable copy of the commutator's tuple. */
662
420
  if (OidIsValid(commId))
663
393
    tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(commId));
664
27
  else
665
27
    tup = NULL;
666
667
  /* Update the commutator's tuple if need be. */
668
420
  if (HeapTupleIsValid(tup))
669
393
  {
670
393
    Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
671
393
    bool    update_commutator = false;
672
673
    /*
674
     * Out of due caution, we only change the commutator's oprcom field if
675
     * it has the exact value we expected: InvalidOid when creating an
676
     * operator, or baseId when dropping one.
677
     */
678
393
    if (isDelete && 
t->oprcom == baseId144
)
679
144
    {
680
144
      t->oprcom = InvalidOid;
681
144
      update_commutator = true;
682
144
    }
683
249
    else if (!isDelete && !OidIsValid(t->oprcom))
684
138
    {
685
138
      t->oprcom = baseId;
686
138
      update_commutator = true;
687
138
    }
688
689
    /* If any columns were found to need modification, update tuple. */
690
393
    if (update_commutator)
691
282
    {
692
282
      CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
693
694
      /*
695
       * Do CCI to make the updated tuple visible.  We must do this in
696
       * case the commutator is also the negator.  (Which would be a
697
       * logic error on the operator definer's part, but that's not a
698
       * good reason to fail here.)  We would need a CCI anyway in the
699
       * deletion case for a self-commutator with no negator.
700
       */
701
282
      CommandCounterIncrement();
702
282
    }
703
393
  }
704
705
  /*
706
   * Similarly find and update the negator, if any.
707
   */
708
420
  if (OidIsValid(negId))
709
298
    tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(negId));
710
122
  else
711
122
    tup = NULL;
712
713
420
  if (HeapTupleIsValid(tup))
714
298
  {
715
298
    Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
716
298
    bool    update_negator = false;
717
718
    /*
719
     * Out of due caution, we only change the negator's oprnegate field if
720
     * it has the exact value we expected: InvalidOid when creating an
721
     * operator, or baseId when dropping one.
722
     */
723
298
    if (isDelete && 
t->oprnegate == baseId101
)
724
101
    {
725
101
      t->oprnegate = InvalidOid;
726
101
      update_negator = true;
727
101
    }
728
197
    else if (!isDelete && !OidIsValid(t->oprnegate))
729
101
    {
730
101
      t->oprnegate = baseId;
731
101
      update_negator = true;
732
101
    }
733
734
    /* If any columns were found to need modification, update tuple. */
735
298
    if (update_negator)
736
202
    {
737
202
      CatalogTupleUpdate(pg_operator_desc, &tup->t_self, tup);
738
739
      /*
740
       * In the deletion case, do CCI to make the updated tuple visible.
741
       * We must do this in case the operator is its own negator. (Which
742
       * would be a logic error on the operator definer's part, but
743
       * that's not a good reason to fail here.)
744
       */
745
202
      if (isDelete)
746
101
        CommandCounterIncrement();
747
202
    }
748
298
  }
749
750
  /* Close relation and release catalog lock. */
751
420
  heap_close(pg_operator_desc, RowExclusiveLock);
752
420
}
753
754
/*
755
 * Create dependencies for an operator (either a freshly inserted
756
 * complete operator, a new shell operator, a just-updated shell,
757
 * or an operator that's being modified by ALTER OPERATOR).
758
 *
759
 * NB: the OidIsValid tests in this routine are necessary, in case
760
 * the given operator is a shell.
761
 */
762
ObjectAddress
763
makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
764
532
{
765
532
  Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
766
532
  ObjectAddress myself,
767
532
        referenced;
768
769
532
  myself.classId = OperatorRelationId;
770
532
  myself.objectId = HeapTupleGetOid(tuple);
771
532
  myself.objectSubId = 0;
772
773
  /*
774
   * If we are updating the operator, delete any existing entries, except
775
   * for extension membership which should remain the same.
776
   */
777
532
  if (isUpdate)
778
215
  {
779
215
    deleteDependencyRecordsFor(myself.classId, myself.objectId, true);
780
215
    deleteSharedDependencyRecordsFor(myself.classId, myself.objectId, 0);
781
215
  }
782
783
  /* Dependency on namespace */
784
532
  if (OidIsValid(oper->oprnamespace))
785
532
  {
786
532
    referenced.classId = NamespaceRelationId;
787
532
    referenced.objectId = oper->oprnamespace;
788
532
    referenced.objectSubId = 0;
789
532
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
790
532
  }
791
792
  /* Dependency on left type */
793
532
  if (OidIsValid(oper->oprleft))
794
527
  {
795
527
    referenced.classId = TypeRelationId;
796
527
    referenced.objectId = oper->oprleft;
797
527
    referenced.objectSubId = 0;
798
527
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
799
527
  }
800
801
  /* Dependency on right type */
802
532
  if (OidIsValid(oper->oprright))
803
528
  {
804
528
    referenced.classId = TypeRelationId;
805
528
    referenced.objectId = oper->oprright;
806
528
    referenced.objectSubId = 0;
807
528
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
808
528
  }
809
810
  /* Dependency on result type */
811
532
  if (OidIsValid(oper->oprresult))
812
384
  {
813
384
    referenced.classId = TypeRelationId;
814
384
    referenced.objectId = oper->oprresult;
815
384
    referenced.objectSubId = 0;
816
384
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
817
384
  }
818
819
  /*
820
   * NOTE: we do not consider the operator to depend on the associated
821
   * operators oprcom and oprnegate. We would not want to delete this
822
   * operator if those go away, but only reset the link fields; which is not
823
   * a function that the dependency code can presently handle.  (Something
824
   * could perhaps be done with objectSubId though.)  For now, it's okay to
825
   * let those links dangle if a referenced operator is removed.
826
   */
827
828
  /* Dependency on implementation function */
829
532
  if (OidIsValid(oper->oprcode))
830
384
  {
831
384
    referenced.classId = ProcedureRelationId;
832
384
    referenced.objectId = oper->oprcode;
833
384
    referenced.objectSubId = 0;
834
384
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
835
384
  }
836
837
  /* Dependency on restriction selectivity function */
838
532
  if (OidIsValid(oper->oprrest))
839
297
  {
840
297
    referenced.classId = ProcedureRelationId;
841
297
    referenced.objectId = oper->oprrest;
842
297
    referenced.objectSubId = 0;
843
297
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
844
297
  }
845
846
  /* Dependency on join selectivity function */
847
532
  if (OidIsValid(oper->oprjoin))
848
296
  {
849
296
    referenced.classId = ProcedureRelationId;
850
296
    referenced.objectId = oper->oprjoin;
851
296
    referenced.objectSubId = 0;
852
296
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
853
296
  }
854
855
  /* Dependency on owner */
856
532
  recordDependencyOnOwner(OperatorRelationId, HeapTupleGetOid(tuple),
857
532
              oper->oprowner);
858
859
  /* Dependency on extension */
860
532
  recordDependencyOnCurrentExtension(&myself, true);
861
862
532
  return myself;
863
532
}