PostgreSQL Source Code git master
Loading...
Searching...
No Matches
operatorcmds.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for operatorcmds.c:

Go to the source code of this file.

Functions

static Oid ValidateRestrictionEstimator (List *restrictionName)
 
static Oid ValidateJoinEstimator (List *joinName)
 
static Oid ValidateOperatorReference (List *name, Oid leftTypeId, Oid rightTypeId)
 
ObjectAddress DefineOperator (List *names, List *parameters)
 
void RemoveOperatorById (Oid operOid)
 
ObjectAddress AlterOperator (AlterOperatorStmt *stmt)
 

Function Documentation

◆ AlterOperator()

ObjectAddress AlterOperator ( AlterOperatorStmt stmt)

Definition at line 462 of file operatorcmds.c.

463{
464 ObjectAddress address;
465 Oid oprId;
469 int i;
470 ListCell *pl;
472 bool nulls[Natts_pg_operator];
474 List *restrictionName = NIL; /* optional restrict. sel. function */
475 bool updateRestriction = false;
477 List *joinName = NIL; /* optional join sel. function */
478 bool updateJoin = false;
479 Oid joinOid;
480 List *commutatorName = NIL; /* optional commutator operator name */
482 List *negatorName = NIL; /* optional negator operator name */
484 bool canMerge = false;
485 bool updateMerges = false;
486 bool canHash = false;
487 bool updateHashes = false;
488
489 /* Look up the operator */
490 oprId = LookupOperWithArgs(stmt->opername, false);
493 if (!HeapTupleIsValid(tup))
494 elog(ERROR, "cache lookup failed for operator %u", oprId);
496
497 /* Process options */
498 foreach(pl, stmt->options)
499 {
500 DefElem *defel = (DefElem *) lfirst(pl);
501 List *param;
502
503 if (defel->arg == NULL)
504 param = NIL; /* NONE, removes the function */
505 else
506 param = defGetQualifiedName(defel);
507
508 if (strcmp(defel->defname, "restrict") == 0)
509 {
510 restrictionName = param;
511 updateRestriction = true;
512 }
513 else if (strcmp(defel->defname, "join") == 0)
514 {
515 joinName = param;
516 updateJoin = true;
517 }
518 else if (strcmp(defel->defname, "commutator") == 0)
519 {
521 }
522 else if (strcmp(defel->defname, "negator") == 0)
523 {
525 }
526 else if (strcmp(defel->defname, "merges") == 0)
527 {
529 updateMerges = true;
530 }
531 else if (strcmp(defel->defname, "hashes") == 0)
532 {
534 updateHashes = true;
535 }
536
537 /*
538 * The rest of the options that CREATE accepts cannot be changed.
539 * Check for them so that we can give a meaningful error message.
540 */
541 else if (strcmp(defel->defname, "leftarg") == 0 ||
542 strcmp(defel->defname, "rightarg") == 0 ||
543 strcmp(defel->defname, "function") == 0 ||
544 strcmp(defel->defname, "procedure") == 0)
545 {
548 errmsg("operator attribute \"%s\" cannot be changed",
549 defel->defname)));
550 }
551 else
554 errmsg("operator attribute \"%s\" not recognized",
555 defel->defname)));
556 }
557
558 /* Check permissions. Must be owner. */
561 NameStr(oprForm->oprname));
562
563 /*
564 * Look up OIDs for any parameters specified
565 */
566 if (restrictionName)
568 else
570 if (joinName)
572 else
574
575 if (commutatorName)
576 {
577 /* commutator has reversed arg types */
579 oprForm->oprright,
580 oprForm->oprleft);
581
582 /*
583 * We don't need to do anything extra for a self commutator as in
584 * OperatorCreate, since the operator surely exists already.
585 */
586 }
587 else
589
590 if (negatorName)
591 {
593 oprForm->oprleft,
594 oprForm->oprright);
595
596 /* Must reject self-negation */
597 if (negatorOid == oprForm->oid)
600 errmsg("operator cannot be its own negator")));
601 }
602 else
603 {
605 }
606
607 /*
608 * Check that we're not changing any attributes that might be depended on
609 * by plans, while allowing no-op updates.
610 */
611 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
612 commutatorOid != oprForm->oprcom)
615 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
616 "commutator")));
617
618 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
619 negatorOid != oprForm->oprnegate)
622 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
623 "negator")));
624
625 if (updateMerges && oprForm->oprcanmerge && !canMerge)
628 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
629 "merges")));
630
631 if (updateHashes && oprForm->oprcanhash && !canHash)
634 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
635 "hashes")));
636
637 /* Perform additional checks, like OperatorCreate does */
639 oprForm->oprright,
640 oprForm->oprresult,
645 canMerge,
646 canHash);
647
648 /* Update the tuple */
649 for (i = 0; i < Natts_pg_operator; ++i)
650 {
651 values[i] = (Datum) 0;
652 replaces[i] = false;
653 nulls[i] = false;
654 }
656 {
659 }
660 if (updateJoin)
661 {
664 }
666 {
669 }
671 {
674 }
675 if (updateMerges)
676 {
679 }
680 if (updateHashes)
681 {
684 }
685
687 values, nulls, replaces);
688
689 CatalogTupleUpdate(catalog, &tup->t_self, tup);
690
691 address = makeOperatorDependencies(tup, false, true);
692
695
697
699
700 return address;
701}
@ ACLCHECK_NOT_OWNER
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2654
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4090
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define NameStr(name)
Definition c.h:765
#define OidIsValid(objectId)
Definition c.h:788
bool defGetBoolean(DefElem *def)
Definition define.c:93
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition heaptuple.c:1210
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup)
Definition indexing.c:313
int i
Definition isn.c:77
#define NoLock
Definition lockdefs.h:34
#define RowExclusiveLock
Definition lockdefs.h:38
Oid GetUserId(void)
Definition miscinit.c:469
#define InvokeObjectPostAlterHook(classId, objectId, subId)
static Oid ValidateJoinEstimator(List *joinName)
static Oid ValidateOperatorReference(List *name, Oid leftTypeId, Oid rightTypeId)
static Oid ValidateRestrictionEstimator(List *restrictionName)
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition parse_oper.c:134
@ OBJECT_OPERATOR
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
void OperatorValidateParams(Oid leftTypeId, Oid rightTypeId, Oid operResultType, bool hasCommutator, bool hasNegator, bool hasRestrictionSelectivity, bool hasJoinSelectivity, bool canMerge, bool canHash)
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:83
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
#define RelationGetDescr(relation)
Definition rel.h:540
Definition pg_list.h:54
#define SearchSysCacheCopy1(cacheId, key1)
Definition syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40

References aclcheck_error(), ACLCHECK_NOT_OWNER, BoolGetDatum(), CatalogTupleUpdate(), defGetBoolean(), defGetQualifiedName(), elog, ereport, errcode(), errmsg(), ERROR, fb(), GETSTRUCT(), GetUserId(), heap_modify_tuple(), HeapTupleIsValid, i, InvalidOid, InvokeObjectPostAlterHook, lfirst, LookupOperWithArgs(), makeOperatorDependencies(), NameStr, NIL, NoLock, OBJECT_OPERATOR, object_ownercheck(), ObjectIdGetDatum(), OidIsValid, OperatorUpd(), OperatorValidateParams(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, stmt, table_close(), table_open(), ValidateJoinEstimator(), ValidateOperatorReference(), ValidateRestrictionEstimator(), and values.

Referenced by ProcessUtilitySlow().

◆ DefineOperator()

ObjectAddress DefineOperator ( List names,
List parameters 
)

Definition at line 67 of file operatorcmds.c.

68{
69 char *oprName;
72 bool canMerge = false; /* operator merges */
73 bool canHash = false; /* operator hashes */
74 List *functionName = NIL; /* function for operator */
75 TypeName *typeName1 = NULL; /* first type name */
76 TypeName *typeName2 = NULL; /* second type name */
77 Oid typeId1 = InvalidOid; /* types converted to OID */
79 Oid rettype;
80 List *commutatorName = NIL; /* optional commutator operator name */
81 List *negatorName = NIL; /* optional negator operator name */
82 List *restrictionName = NIL; /* optional restrict. sel. function */
83 List *joinName = NIL; /* optional join sel. function */
84 Oid functionOid; /* functions converted to OID */
87 Oid typeId[2]; /* to hold left and right arg */
88 int nargs;
89 ListCell *pl;
90
91 /* Convert list of names to a name and namespace */
93
94 /* Check we have creation rights in target namespace */
99
100 /*
101 * loop over the definition list and extract the information we need.
102 */
103 foreach(pl, parameters)
104 {
105 DefElem *defel = (DefElem *) lfirst(pl);
106
107 if (strcmp(defel->defname, "leftarg") == 0)
108 {
110 if (typeName1->setof)
113 errmsg("SETOF type not allowed for operator argument")));
114 }
115 else if (strcmp(defel->defname, "rightarg") == 0)
116 {
118 if (typeName2->setof)
121 errmsg("SETOF type not allowed for operator argument")));
122 }
123 /* "function" and "procedure" are equivalent here */
124 else if (strcmp(defel->defname, "function") == 0)
126 else if (strcmp(defel->defname, "procedure") == 0)
128 else if (strcmp(defel->defname, "commutator") == 0)
130 else if (strcmp(defel->defname, "negator") == 0)
132 else if (strcmp(defel->defname, "restrict") == 0)
134 else if (strcmp(defel->defname, "join") == 0)
136 else if (strcmp(defel->defname, "hashes") == 0)
138 else if (strcmp(defel->defname, "merges") == 0)
140 /* These obsolete options are taken as meaning canMerge */
141 else if (strcmp(defel->defname, "sort1") == 0)
142 canMerge = true;
143 else if (strcmp(defel->defname, "sort2") == 0)
144 canMerge = true;
145 else if (strcmp(defel->defname, "ltcmp") == 0)
146 canMerge = true;
147 else if (strcmp(defel->defname, "gtcmp") == 0)
148 canMerge = true;
149 else
150 {
151 /* WARNING, not ERROR, for historical backwards-compatibility */
154 errmsg("operator attribute \"%s\" not recognized",
155 defel->defname)));
156 }
157 }
158
159 /*
160 * make sure we have our required definitions
161 */
162 if (functionName == NIL)
165 errmsg("operator function must be specified")));
166
167 /* Transform type names to type OIDs */
168 if (typeName1)
170 if (typeName2)
172
173 /*
174 * If only the right argument is missing, the user is likely trying to
175 * create a postfix operator, so give them a hint about why that does not
176 * work. But if both arguments are missing, do not mention postfix
177 * operators, as the user most likely simply neglected to mention the
178 * arguments.
179 */
183 errmsg("operator argument types must be specified")));
184 if (!OidIsValid(typeId2))
187 errmsg("operator right argument type must be specified"),
188 errdetail("Postfix operators are not supported.")));
189
190 if (typeName1)
191 {
193 if (aclresult != ACLCHECK_OK)
195 }
196
197 if (typeName2)
198 {
200 if (aclresult != ACLCHECK_OK)
202 }
203
204 /*
205 * Look up the operator's underlying function.
206 */
207 if (!OidIsValid(typeId1))
208 {
209 typeId[0] = typeId2;
210 nargs = 1;
211 }
212 else if (!OidIsValid(typeId2))
213 {
214 typeId[0] = typeId1;
215 nargs = 1;
216 }
217 else
218 {
219 typeId[0] = typeId1;
220 typeId[1] = typeId2;
221 nargs = 2;
222 }
223 functionOid = LookupFuncName(functionName, nargs, typeId, false);
224
225 /*
226 * We require EXECUTE rights for the function. This isn't strictly
227 * necessary, since EXECUTE will be checked at any attempted use of the
228 * operator, but it seems like a good idea anyway.
229 */
231 if (aclresult != ACLCHECK_OK)
234
235 rettype = get_func_rettype(functionOid);
237 if (aclresult != ACLCHECK_OK)
239
240 /*
241 * Look up restriction and join estimators if specified
242 */
243 if (restrictionName)
245 else
247 if (joinName)
249 else
251
252 /*
253 * now have OperatorCreate do all the work..
254 */
255 return
256 OperatorCreate(oprName, /* operator name */
257 oprNamespace, /* namespace */
258 typeId1, /* left type id */
259 typeId2, /* right type id */
260 functionOid, /* function for operator */
261 commutatorName, /* optional commutator operator name */
262 negatorName, /* optional negator operator name */
263 restrictionOid, /* optional restrict. sel. function */
264 joinOid, /* optional join sel. function name */
265 canMerge, /* operator merges */
266 canHash); /* operator hashes */
267}
AclResult
Definition acl.h:182
@ ACLCHECK_OK
Definition acl.h:183
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3836
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition aclchk.c:2973
TypeName * defGetTypeName(DefElem *def)
Definition define.c:270
int errdetail(const char *fmt,...)
Definition elog.c:1216
#define WARNING
Definition elog.h:36
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3516
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1805
char * NameListToString(const List *names)
Definition namespace.c:3664
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3557
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition parse_type.c:291
#define ACL_USAGE
Definition parsenodes.h:84
@ OBJECT_SCHEMA
@ OBJECT_FUNCTION
#define ACL_EXECUTE
Definition parsenodes.h:83
#define ACL_CREATE
Definition parsenodes.h:85
ObjectAddress OperatorCreate(const char *operatorName, Oid operatorNamespace, Oid leftTypeId, Oid rightTypeId, Oid procedureId, List *commutatorName, List *negatorName, Oid restrictionId, Oid joinId, bool canMerge, bool canHash)

References ACL_CREATE, ACL_EXECUTE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), ereport, errcode(), errdetail(), errmsg(), ERROR, fb(), get_func_rettype(), get_namespace_name(), GetUserId(), InvalidOid, lfirst, LookupFuncName(), NameListToString(), NIL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_SCHEMA, OidIsValid, OperatorCreate(), QualifiedNameGetCreationNamespace(), typenameTypeId(), ValidateJoinEstimator(), ValidateRestrictionEstimator(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ RemoveOperatorById()

void RemoveOperatorById ( Oid  operOid)

Definition at line 413 of file operatorcmds.c.

414{
415 Relation relation;
418
420
422 if (!HeapTupleIsValid(tup)) /* should not happen */
423 elog(ERROR, "cache lookup failed for operator %u", operOid);
425
426 /*
427 * Reset links from commutator and negator, if any. In case of a
428 * self-commutator or self-negator, this means we have to re-fetch the
429 * updated tuple. (We could optimize away updates on the tuple we're
430 * about to drop, but it doesn't seem worth convoluting the logic for.)
431 */
432 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
433 {
434 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
435 if (operOid == op->oprcom || operOid == op->oprnegate)
436 {
439 if (!HeapTupleIsValid(tup)) /* should not happen */
440 elog(ERROR, "cache lookup failed for operator %u", operOid);
441 }
442 }
443
444 CatalogTupleDelete(relation, &tup->t_self);
445
447
448 table_close(relation, RowExclusiveLock);
449}
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220

References CatalogTupleDelete(), elog, ERROR, fb(), GETSTRUCT(), HeapTupleIsValid, ObjectIdGetDatum(), OidIsValid, OperatorUpd(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), table_close(), and table_open().

Referenced by doDeletion().

◆ ValidateJoinEstimator()

static Oid ValidateJoinEstimator ( List joinName)
static

Definition at line 310 of file operatorcmds.c.

311{
312 Oid typeId[5];
313 Oid joinOid;
316
317 typeId[0] = INTERNALOID; /* PlannerInfo */
318 typeId[1] = OIDOID; /* operator OID */
319 typeId[2] = INTERNALOID; /* args list */
320 typeId[3] = INT2OID; /* jointype */
321 typeId[4] = INTERNALOID; /* SpecialJoinInfo */
322
323 /*
324 * As of Postgres 8.4, the preferred signature for join estimators has 5
325 * arguments, but we still allow the old 4-argument form. Whine about
326 * ambiguity if both forms exist.
327 */
328 joinOid = LookupFuncName(joinName, 5, typeId, true);
329 joinOid2 = LookupFuncName(joinName, 4, typeId, true);
330 if (OidIsValid(joinOid))
331 {
332 if (OidIsValid(joinOid2))
335 errmsg("join estimator function %s has multiple matches",
337 }
338 else
339 {
341 /* If not found, reference the 5-argument signature in error msg */
342 if (!OidIsValid(joinOid))
343 joinOid = LookupFuncName(joinName, 5, typeId, false);
344 }
345
346 /* estimators must return float8 */
350 errmsg("join estimator function %s must return type %s",
351 NameListToString(joinName), "float8")));
352
353 /* Require EXECUTE rights for the estimator */
355 if (aclresult != ACLCHECK_OK)
358
359 return joinOid;
360}

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, fb(), get_func_rettype(), GetUserId(), LookupFuncName(), NameListToString(), object_aclcheck(), OBJECT_FUNCTION, and OidIsValid.

Referenced by AlterOperator(), and DefineOperator().

◆ ValidateOperatorReference()

static Oid ValidateOperatorReference ( List name,
Oid  leftTypeId,
Oid  rightTypeId 
)
static

Definition at line 372 of file operatorcmds.c.

375{
376 Oid oid;
377 bool defined;
378
379 oid = OperatorLookup(name,
382 &defined);
383
384 /* These message strings are chosen to match parse_oper.c */
385 if (!OidIsValid(oid))
388 errmsg("operator does not exist: %s",
391 rightTypeId))));
392
393 if (!defined)
396 errmsg("operator is only a shell: %s",
399 rightTypeId))));
400
404
405 return oid;
406}
const char * op_signature_string(List *op, Oid arg1, Oid arg2)
Definition parse_oper.c:607
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
const char * name

References aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, fb(), GetUserId(), name, NameListToString(), OBJECT_OPERATOR, object_ownercheck(), OidIsValid, op_signature_string(), and OperatorLookup().

Referenced by AlterOperator().

◆ ValidateRestrictionEstimator()

static Oid ValidateRestrictionEstimator ( List restrictionName)
static

Definition at line 275 of file operatorcmds.c.

276{
277 Oid typeId[4];
280
281 typeId[0] = INTERNALOID; /* PlannerInfo */
282 typeId[1] = OIDOID; /* operator OID */
283 typeId[2] = INTERNALOID; /* args list */
284 typeId[3] = INT4OID; /* varRelid */
285
286 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
287
288 /* estimators must return float8 */
292 errmsg("restriction estimator function %s must return type %s",
293 NameListToString(restrictionName), "float8")));
294
295 /* Require EXECUTE rights for the estimator */
297 if (aclresult != ACLCHECK_OK)
300
301 return restrictionOid;
302}

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, fb(), get_func_rettype(), GetUserId(), LookupFuncName(), NameListToString(), object_aclcheck(), and OBJECT_FUNCTION.

Referenced by AlterOperator(), and DefineOperator().