1
/*-------------------------------------------------------------------------
4
* routines to support manipulation of the pg_operator relation
6
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
7
* Portions Copyright (c) 1994, Regents of the University of California
11
* $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.87 2004-12-31 21:59:38 pgsql Exp $
14
* these routines moved here from commands/define.c and somewhat cleaned up.
16
*-------------------------------------------------------------------------
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"
36
static Oid OperatorGet(const char *operatorName,
37
Oid operatorNamespace,
42
static Oid OperatorLookup(List *operatorName,
47
static Oid OperatorShellMake(const char *operatorName,
48
Oid operatorNamespace,
52
static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
54
static Oid get_other_operator(List *otherOp,
55
Oid otherLeftTypeId, Oid otherRightTypeId,
56
const char *operatorName, Oid operatorNamespace,
57
Oid leftTypeId, Oid rightTypeId,
60
static void makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid);
64
* Check whether a proposed operator name is legal
66
* This had better match the behavior of parser/scan.l!
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.
73
validOperatorName(const char *name)
75
size_t len = strlen(name);
77
/* Can't be empty or too long */
78
if (len == 0 || len >= NAMEDATALEN)
81
/* Can't contain any invalid characters */
82
/* Test string here should match op_chars in scan.l */
83
if (strspn(name, "~!@#^&|`?+-*/%<>=") != len)
86
/* Can't contain slash-star or dash-dash (comment starts) */
87
if (strstr(name, "/*") || strstr(name, "--"))
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
98
(name[len - 1] == '+' ||
99
name[len - 1] == '-'))
103
for (ic = len - 2; ic >= 0; ic--)
105
if (strchr("~!@#^&|`?%", name[ic]))
109
return false; /* nope, not valid */
112
/* != isn't valid either, because parser will convert it to <> */
113
if (strcmp(name, "!=") == 0)
123
* finds an operator given an exact specification (name, namespace,
124
* left and right type IDs).
126
* *defined is set TRUE if defined (not a shell)
129
OperatorGet(const char *operatorName,
130
Oid operatorNamespace,
136
Oid operatorObjectId;
138
tup = SearchSysCache(OPERNAMENSP,
139
PointerGetDatum(operatorName),
140
ObjectIdGetDatum(leftObjectId),
141
ObjectIdGetDatum(rightObjectId),
142
ObjectIdGetDatum(operatorNamespace));
143
if (HeapTupleIsValid(tup))
145
RegProcedure oprcode = ((Form_pg_operator) GETSTRUCT(tup))->oprcode;
147
operatorObjectId = HeapTupleGetOid(tup);
148
*defined = RegProcedureIsValid(oprcode);
149
ReleaseSysCache(tup);
153
operatorObjectId = InvalidOid;
157
return operatorObjectId;
163
* looks up an operator given a possibly-qualified name and
164
* left and right type IDs.
166
* *defined is set TRUE if defined (not a shell)
169
OperatorLookup(List *operatorName,
174
Oid operatorObjectId;
175
RegProcedure oprcode;
177
operatorObjectId = LookupOperName(operatorName, leftObjectId,
178
rightObjectId, true);
179
if (!OidIsValid(operatorObjectId))
185
oprcode = get_opcode(operatorObjectId);
186
*defined = RegProcedureIsValid(oprcode);
188
return operatorObjectId;
194
* Make a "shell" entry for a not-yet-existing operator.
197
OperatorShellMake(const char *operatorName,
198
Oid operatorNamespace,
202
Relation pg_operator_desc;
203
Oid operatorObjectId;
206
Datum values[Natts_pg_operator];
207
char nulls[Natts_pg_operator];
212
* validate operator name
214
if (!validOperatorName(operatorName))
216
(errcode(ERRCODE_INVALID_NAME),
217
errmsg("\"%s\" is not a valid operator name",
221
* initialize our *nulls and *values arrays
223
for (i = 0; i < Natts_pg_operator; ++i)
226
values[i] = (Datum) NULL; /* redundant, but safe */
230
* initialize values[] with the operator name and input data types.
231
* Note that oprcode is set to InvalidOid, indicating it's a shell.
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 */
256
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
257
tupDesc = pg_operator_desc->rd_att;
260
* create a new operator tuple
262
tup = heap_formtuple(tupDesc, values, nulls);
265
* insert our "shell" operator tuple
267
operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
269
CatalogUpdateIndexes(pg_operator_desc, tup);
271
/* Add dependencies for the entry */
272
makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));
277
* close the operator relation and return the oid.
279
heap_close(pg_operator_desc, RowExclusiveLock);
281
return operatorObjectId;
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)
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.
319
* check if operator already defined
320
* if so, but oprcode is null, save the Oid -- we are filling in a shell
322
* get the attribute types from relation descriptor for pg_operator
323
* assign values to the fields of the operator:
325
* owner id (simply the user id of the caller)
326
* operator "kind" either "b" for binary or "l" for left unary
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
361
OperatorCreate(const char *operatorName,
362
Oid operatorNamespace,
366
List *commutatorName,
368
List *restrictionName,
376
Relation pg_operator_desc;
378
char nulls[Natts_pg_operator];
379
char replaces[Natts_pg_operator];
380
Datum values[Natts_pg_operator];
381
Oid operatorObjectId;
382
bool operatorAlreadyDefined;
393
bool selfCommutator = false;
394
Oid typeId[FUNC_MAX_ARGS];
403
if (!validOperatorName(operatorName))
405
(errcode(ERRCODE_INVALID_NAME),
406
errmsg("\"%s\" is not a valid operator name",
409
if (!OidIsValid(leftTypeId) && !OidIsValid(rightTypeId))
411
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
412
errmsg("at least one of leftarg or rightarg must be specified")));
414
if (!(OidIsValid(leftTypeId) && OidIsValid(rightTypeId)))
416
/* If it's not a binary op, these things mustn't be set: */
419
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
420
errmsg("only binary operators can have commutators")));
423
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
424
errmsg("only binary operators can have join selectivity")));
427
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
428
errmsg("only binary operators can hash")));
429
if (leftSortName || rightSortName || ltCompareName || gtCompareName)
431
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
432
errmsg("only binary operators can merge join")));
435
operatorObjectId = OperatorGet(operatorName,
439
&operatorAlreadyDefined);
441
if (operatorAlreadyDefined)
443
(errcode(ERRCODE_DUPLICATE_FUNCTION),
444
errmsg("operator %s already exists",
448
* At this point, if operatorObjectId is not InvalidOid then we are
449
* filling in a previously-created shell.
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.
457
MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
458
if (!OidIsValid(leftTypeId))
460
typeId[0] = rightTypeId;
463
else if (!OidIsValid(rightTypeId))
465
typeId[0] = leftTypeId;
470
typeId[0] = leftTypeId;
471
typeId[1] = rightTypeId;
474
procOid = LookupFuncName(procedureName, nargs, typeId, false);
475
operResultType = get_func_rettype(procOid);
478
* find restriction estimator
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 */
488
restOid = LookupFuncName(restrictionName, 4, typeId, false);
491
restOid = InvalidOid;
494
* find join estimator
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 */
504
joinOid = LookupFuncName(joinName, 4, typeId, false);
507
joinOid = InvalidOid;
510
* set up values in the operator tuple
513
for (i = 0; i < Natts_pg_operator; ++i)
515
values[i] = (Datum) NULL;
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 */
532
* Set up the other operators. If they do not currently exist, create
533
* shells in order to get ObjectId's.
538
/* commutator has reversed arg types */
539
commutatorId = get_other_operator(commutatorName,
540
rightTypeId, leftTypeId,
541
operatorName, operatorNamespace,
542
leftTypeId, rightTypeId,
546
* self-linkage to this operator; will fix below. Note that only
547
* self-linkage for commutation makes sense.
549
if (!OidIsValid(commutatorId))
550
selfCommutator = true;
553
commutatorId = InvalidOid;
554
values[i++] = ObjectIdGetDatum(commutatorId); /* oprcom */
558
/* negator has same arg types */
559
negatorId = get_other_operator(negatorName,
560
leftTypeId, rightTypeId,
561
operatorName, operatorNamespace,
562
leftTypeId, rightTypeId,
566
negatorId = InvalidOid;
567
values[i++] = ObjectIdGetDatum(negatorId); /* oprnegate */
571
/* left sort op takes left-side data type */
572
leftSortId = get_other_operator(leftSortName,
573
leftTypeId, leftTypeId,
574
operatorName, operatorNamespace,
575
leftTypeId, rightTypeId,
579
leftSortId = InvalidOid;
580
values[i++] = ObjectIdGetDatum(leftSortId); /* oprlsortop */
584
/* right sort op takes right-side data type */
585
rightSortId = get_other_operator(rightSortName,
586
rightTypeId, rightTypeId,
587
operatorName, operatorNamespace,
588
leftTypeId, rightTypeId,
592
rightSortId = InvalidOid;
593
values[i++] = ObjectIdGetDatum(rightSortId); /* oprrsortop */
597
/* comparator has same arg types */
598
ltCompareId = get_other_operator(ltCompareName,
599
leftTypeId, rightTypeId,
600
operatorName, operatorNamespace,
601
leftTypeId, rightTypeId,
605
ltCompareId = InvalidOid;
606
values[i++] = ObjectIdGetDatum(ltCompareId); /* oprltcmpop */
610
/* comparator has same arg types */
611
gtCompareId = get_other_operator(gtCompareName,
612
leftTypeId, rightTypeId,
613
operatorName, operatorNamespace,
614
leftTypeId, rightTypeId,
618
gtCompareId = InvalidOid;
619
values[i++] = ObjectIdGetDatum(gtCompareId); /* oprgtcmpop */
621
values[i++] = ObjectIdGetDatum(procOid); /* oprcode */
622
values[i++] = ObjectIdGetDatum(restOid); /* oprrest */
623
values[i++] = ObjectIdGetDatum(joinOid); /* oprjoin */
625
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
628
* If we are adding to an operator shell, update; else insert
630
if (operatorObjectId)
632
tup = SearchSysCacheCopy(OPEROID,
633
ObjectIdGetDatum(operatorObjectId),
635
if (!HeapTupleIsValid(tup))
636
elog(ERROR, "cache lookup failed for operator %u",
639
tup = heap_modifytuple(tup,
645
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
649
tupDesc = pg_operator_desc->rd_att;
650
tup = heap_formtuple(tupDesc, values, nulls);
652
operatorObjectId = simple_heap_insert(pg_operator_desc, tup);
655
/* Must update the indexes in either case */
656
CatalogUpdateIndexes(pg_operator_desc, tup);
658
/* Add dependencies for the entry */
659
makeOperatorDependencies(tup, RelationGetRelid(pg_operator_desc));
661
heap_close(pg_operator_desc, RowExclusiveLock);
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.
675
commutatorId = operatorObjectId;
677
if (OidIsValid(commutatorId) || OidIsValid(negatorId))
678
OperatorUpd(operatorObjectId, commutatorId, negatorId);
682
* Try to lookup another operator (commutator, etc)
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.
690
get_other_operator(List *otherOp, Oid otherLeftTypeId, Oid otherRightTypeId,
691
const char *operatorName, Oid operatorNamespace,
692
Oid leftTypeId, Oid rightTypeId, bool isCommutator)
700
other_oid = OperatorLookup(otherOp,
705
if (OidIsValid(other_oid))
707
/* other op already in catalogs */
711
otherNamespace = QualifiedNameGetCreationNamespace(otherOp,
714
if (strcmp(otherName, operatorName) == 0 &&
715
otherNamespace == operatorNamespace &&
716
otherLeftTypeId == leftTypeId &&
717
otherRightTypeId == rightTypeId)
720
* self-linkage to this operator; caller will fix later. Note that
721
* only self-linkage for commutation makes sense.
725
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
726
errmsg("operator cannot be its own negator or sort operator")));
730
/* not in catalogs, different from operator, so make shell */
732
aclresult = pg_namespace_aclcheck(otherNamespace, GetUserId(),
734
if (aclresult != ACLCHECK_OK)
735
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
736
get_namespace_name(otherNamespace));
738
other_oid = OperatorShellMake(otherName,
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.
755
OperatorUpd(Oid baseId, Oid commId, Oid negId)
758
Relation pg_operator_desc;
760
char nulls[Natts_pg_operator];
761
char replaces[Natts_pg_operator];
762
Datum values[Natts_pg_operator];
764
for (i = 0; i < Natts_pg_operator; ++i)
766
values[i] = (Datum) 0;
772
* check and update the commutator & negator, if necessary
774
* First make sure we can see them...
776
CommandCounterIncrement();
778
pg_operator_desc = heap_openr(OperatorRelationName, RowExclusiveLock);
780
tup = SearchSysCacheCopy(OPEROID,
781
ObjectIdGetDatum(commId),
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...
791
if (HeapTupleIsValid(tup))
793
Form_pg_operator t = (Form_pg_operator) GETSTRUCT(tup);
795
if (!OidIsValid(t->oprcom) || !OidIsValid(t->oprnegate))
797
if (!OidIsValid(t->oprnegate))
799
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
800
replaces[Anum_pg_operator_oprnegate - 1] = 'r';
803
if (!OidIsValid(t->oprcom))
805
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
806
replaces[Anum_pg_operator_oprcom - 1] = 'r';
809
tup = heap_modifytuple(tup,
815
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
817
CatalogUpdateIndexes(pg_operator_desc, tup);
821
heap_close(pg_operator_desc, RowExclusiveLock);
826
/* if commutator and negator are different, do two updates */
828
if (HeapTupleIsValid(tup) &&
829
!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprcom)))
831
values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(baseId);
832
replaces[Anum_pg_operator_oprcom - 1] = 'r';
834
tup = heap_modifytuple(tup,
840
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
842
CatalogUpdateIndexes(pg_operator_desc, tup);
844
values[Anum_pg_operator_oprcom - 1] = (Datum) NULL;
845
replaces[Anum_pg_operator_oprcom - 1] = ' ';
848
/* check and update the negator, if necessary */
850
tup = SearchSysCacheCopy(OPEROID,
851
ObjectIdGetDatum(negId),
854
if (HeapTupleIsValid(tup) &&
855
!(OidIsValid(((Form_pg_operator) GETSTRUCT(tup))->oprnegate)))
857
values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(baseId);
858
replaces[Anum_pg_operator_oprnegate - 1] = 'r';
860
tup = heap_modifytuple(tup,
866
simple_heap_update(pg_operator_desc, &tup->t_self, tup);
868
CatalogUpdateIndexes(pg_operator_desc, tup);
871
heap_close(pg_operator_desc, RowExclusiveLock);
875
* Create dependencies for a new operator (either a freshly inserted
876
* complete operator, a new shell operator, or a just-updated shell).
878
* NB: the OidIsValid tests in this routine are necessary, in case
879
* the given operator is a shell.
882
makeOperatorDependencies(HeapTuple tuple, Oid pg_operator_relid)
884
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
885
ObjectAddress myself,
888
myself.classId = pg_operator_relid;
889
myself.objectId = HeapTupleGetOid(tuple);
890
myself.objectSubId = 0;
892
/* In case we are updating a shell, delete any existing entries */
893
deleteDependencyRecordsFor(myself.classId, myself.objectId);
895
/* Dependency on namespace */
896
if (OidIsValid(oper->oprnamespace))
898
referenced.classId = get_system_catalog_relid(NamespaceRelationName);
899
referenced.objectId = oper->oprnamespace;
900
referenced.objectSubId = 0;
901
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
904
/* Dependency on left type */
905
if (OidIsValid(oper->oprleft))
907
referenced.classId = RelOid_pg_type;
908
referenced.objectId = oper->oprleft;
909
referenced.objectSubId = 0;
910
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
913
/* Dependency on right type */
914
if (OidIsValid(oper->oprright))
916
referenced.classId = RelOid_pg_type;
917
referenced.objectId = oper->oprright;
918
referenced.objectSubId = 0;
919
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
922
/* Dependency on result type */
923
if (OidIsValid(oper->oprresult))
925
referenced.classId = RelOid_pg_type;
926
referenced.objectId = oper->oprresult;
927
referenced.objectSubId = 0;
928
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
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.
941
/* Dependency on implementation function */
942
if (OidIsValid(oper->oprcode))
944
referenced.classId = RelOid_pg_proc;
945
referenced.objectId = oper->oprcode;
946
referenced.objectSubId = 0;
947
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
950
/* Dependency on restriction selectivity function */
951
if (OidIsValid(oper->oprrest))
953
referenced.classId = RelOid_pg_proc;
954
referenced.objectId = oper->oprrest;
955
referenced.objectSubId = 0;
956
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
959
/* Dependency on join selectivity function */
960
if (OidIsValid(oper->oprjoin))
962
referenced.classId = RelOid_pg_proc;
963
referenced.objectId = oper->oprjoin;
964
referenced.objectSubId = 0;
965
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);