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 495 of file operatorcmds.c.

496{
497 ObjectAddress address;
498 Oid oprId;
502 int i;
503 ListCell *pl;
505 bool nulls[Natts_pg_operator];
507 List *restrictionName = NIL; /* optional restrict. sel. function */
508 bool updateRestriction = false;
510 List *joinName = NIL; /* optional join sel. function */
511 bool updateJoin = false;
512 Oid joinOid;
513 List *commutatorName = NIL; /* optional commutator operator name */
515 List *negatorName = NIL; /* optional negator operator name */
517 bool canMerge = false;
518 bool updateMerges = false;
519 bool canHash = false;
520 bool updateHashes = false;
521
522 /* Look up the operator */
523 oprId = LookupOperWithArgs(stmt->opername, false);
526 if (!HeapTupleIsValid(tup))
527 elog(ERROR, "cache lookup failed for operator %u", oprId);
529
530 /* Process options */
531 foreach(pl, stmt->options)
532 {
533 DefElem *defel = (DefElem *) lfirst(pl);
534 List *param;
535
536 if (defel->arg == NULL)
537 param = NIL; /* NONE, removes the function */
538 else
539 param = defGetQualifiedName(defel);
540
541 if (strcmp(defel->defname, "restrict") == 0)
542 {
543 restrictionName = param;
544 updateRestriction = true;
545 }
546 else if (strcmp(defel->defname, "join") == 0)
547 {
548 joinName = param;
549 updateJoin = true;
550 }
551 else if (strcmp(defel->defname, "commutator") == 0)
552 {
554 }
555 else if (strcmp(defel->defname, "negator") == 0)
556 {
558 }
559 else if (strcmp(defel->defname, "merges") == 0)
560 {
562 updateMerges = true;
563 }
564 else if (strcmp(defel->defname, "hashes") == 0)
565 {
567 updateHashes = true;
568 }
569
570 /*
571 * The rest of the options that CREATE accepts cannot be changed.
572 * Check for them so that we can give a meaningful error message.
573 */
574 else if (strcmp(defel->defname, "leftarg") == 0 ||
575 strcmp(defel->defname, "rightarg") == 0 ||
576 strcmp(defel->defname, "function") == 0 ||
577 strcmp(defel->defname, "procedure") == 0)
578 {
581 errmsg("operator attribute \"%s\" cannot be changed",
582 defel->defname)));
583 }
584 else
587 errmsg("operator attribute \"%s\" not recognized",
588 defel->defname)));
589 }
590
591 /* Check permissions. Must be owner. */
594 NameStr(oprForm->oprname));
595
596 /*
597 * Look up OIDs for any parameters specified
598 */
599 if (restrictionName)
601 else
603 if (joinName)
605 else
607
608 if (commutatorName)
609 {
610 /* commutator has reversed arg types */
612 oprForm->oprright,
613 oprForm->oprleft);
614
615 /*
616 * We don't need to do anything extra for a self commutator as in
617 * OperatorCreate, since the operator surely exists already.
618 */
619 }
620 else
622
623 if (negatorName)
624 {
626 oprForm->oprleft,
627 oprForm->oprright);
628
629 /* Must reject self-negation */
630 if (negatorOid == oprForm->oid)
633 errmsg("operator cannot be its own negator")));
634 }
635 else
636 {
638 }
639
640 /*
641 * Check that we're not changing any attributes that might be depended on
642 * by plans, while allowing no-op updates.
643 */
644 if (OidIsValid(commutatorOid) && OidIsValid(oprForm->oprcom) &&
645 commutatorOid != oprForm->oprcom)
648 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
649 "commutator")));
650
651 if (OidIsValid(negatorOid) && OidIsValid(oprForm->oprnegate) &&
652 negatorOid != oprForm->oprnegate)
655 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
656 "negator")));
657
658 if (updateMerges && oprForm->oprcanmerge && !canMerge)
661 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
662 "merges")));
663
664 if (updateHashes && oprForm->oprcanhash && !canHash)
667 errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
668 "hashes")));
669
670 /* Perform additional checks, like OperatorCreate does */
672 oprForm->oprright,
673 oprForm->oprresult,
678 canMerge,
679 canHash);
680
681 /* Update the tuple */
682 for (i = 0; i < Natts_pg_operator; ++i)
683 {
684 values[i] = (Datum) 0;
685 replaces[i] = false;
686 nulls[i] = false;
687 }
689 {
692 }
693 if (updateJoin)
694 {
697 }
699 {
702 }
704 {
707 }
708 if (updateMerges)
709 {
712 }
713 if (updateHashes)
714 {
717 }
718
720 values, nulls, replaces);
721
722 CatalogTupleUpdate(catalog, &tup->t_self, tup);
723
724 address = makeOperatorDependencies(tup, false, true);
725
728
730
732
733 return address;
734}
@ 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:4108
static Datum values[MAXATTR]
Definition bootstrap.c:147
#define NameStr(name)
Definition c.h:777
#define OidIsValid(objectId)
Definition c.h:800
bool defGetBoolean(DefElem *def)
Definition define.c:93
List * defGetQualifiedName(DefElem *def)
Definition define.c:238
int errcode(int sqlerrcode)
Definition elog.c:874
int errmsg(const char *fmt,...)
Definition elog.c:1093
#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:135
@ 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)
END_CATALOG_STRUCT typedef FormData_pg_operator * Form_pg_operator
Definition pg_operator.h:87
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(), Form_pg_operator, 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:3854
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,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:36
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3518
Oid get_func_rettype(Oid funcid)
Definition lsyscache.c:1805
char * NameListToString(const List *names)
Definition namespace.c:3666
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition namespace.c:3559
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 446 of file operatorcmds.c.

447{
448 Relation relation;
451
453
455 if (!HeapTupleIsValid(tup)) /* should not happen */
456 elog(ERROR, "cache lookup failed for operator %u", operOid);
458
459 /*
460 * Reset links from commutator and negator, if any. In case of a
461 * self-commutator or self-negator, this means we have to re-fetch the
462 * updated tuple. (We could optimize away updates on the tuple we're
463 * about to drop, but it doesn't seem worth convoluting the logic for.)
464 */
465 if (OidIsValid(op->oprcom) || OidIsValid(op->oprnegate))
466 {
467 OperatorUpd(operOid, op->oprcom, op->oprnegate, true);
468 if (operOid == op->oprcom || operOid == op->oprnegate)
469 {
472 if (!HeapTupleIsValid(tup)) /* should not happen */
473 elog(ERROR, "cache lookup failed for operator %u", operOid);
474 }
475 }
476
477 CatalogTupleDelete(relation, &tup->t_self);
478
480
481 table_close(relation, RowExclusiveLock);
482}
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:220

References CatalogTupleDelete(), elog, ERROR, fb(), Form_pg_operator, 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 331 of file operatorcmds.c.

332{
333 Oid typeId[5];
334 Oid joinOid;
336
337 typeId[0] = INTERNALOID; /* PlannerInfo */
338 typeId[1] = OIDOID; /* operator OID */
339 typeId[2] = INTERNALOID; /* args list */
340 typeId[3] = INT2OID; /* jointype */
341 typeId[4] = INTERNALOID; /* SpecialJoinInfo */
342
343 /*
344 * As of Postgres 8.4, the preferred signature for join estimators has 5
345 * arguments, but we still allow the old 4-argument form. Whine about
346 * ambiguity if both forms exist.
347 */
348 joinOid = LookupFuncName(joinName, 5, typeId, true);
349 joinOid2 = LookupFuncName(joinName, 4, typeId, true);
350 if (OidIsValid(joinOid))
351 {
352 if (OidIsValid(joinOid2))
355 errmsg("join estimator function %s has multiple matches",
357 }
358 else
359 {
361 /* If not found, reference the 5-argument signature in error msg */
362 if (!OidIsValid(joinOid))
363 joinOid = LookupFuncName(joinName, 5, typeId, false);
364 }
365
366 /* estimators must return float8 */
370 errmsg("join estimator function %s must return type %s",
371 NameListToString(joinName), "float8")));
372
373 /* privilege checks are the same as in ValidateRestrictionEstimator */
375 {
376 if (!superuser())
379 errmsg("must be superuser to specify a non-built-in join estimator function")));
380 }
381 else
382 {
384
387 if (aclresult != ACLCHECK_OK)
390 }
391
392 return joinOid;
393}
bool superuser(void)
Definition superuser.c:47
#define FirstGenbkiObjectId
Definition transam.h:195

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

Referenced by AlterOperator(), and DefineOperator().

◆ ValidateOperatorReference()

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

Definition at line 405 of file operatorcmds.c.

408{
409 Oid oid;
410 bool defined;
411
412 oid = OperatorLookup(name,
415 &defined);
416
417 /* These message strings are chosen to match parse_oper.c */
418 if (!OidIsValid(oid))
421 errmsg("operator does not exist: %s",
424 rightTypeId))));
425
426 if (!defined)
429 errmsg("operator is only a shell: %s",
432 rightTypeId))));
433
437
438 return oid;
439}
const char * op_signature_string(List *op, Oid arg1, Oid arg2)
Definition parse_oper.c:608
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];
279
280 typeId[0] = INTERNALOID; /* PlannerInfo */
281 typeId[1] = OIDOID; /* operator OID */
282 typeId[2] = INTERNALOID; /* args list */
283 typeId[3] = INT4OID; /* varRelid */
284
285 restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);
286
287 /* estimators must return float8 */
291 errmsg("restriction estimator function %s must return type %s",
292 NameListToString(restrictionName), "float8")));
293
294 /*
295 * If the estimator is not a built-in function, require superuser
296 * privilege to install it. This protects against using something that is
297 * not a restriction estimator or has hard-wired assumptions about what
298 * data types it is working with. (Built-in estimators are required to
299 * defend themselves adequately against unexpected data type choices, but
300 * it seems impractical to expect that of extensions' estimators.)
301 *
302 * If it is built-in, only require EXECUTE rights.
303 */
305 {
306 if (!superuser())
309 errmsg("must be superuser to specify a non-built-in restriction estimator function")));
310 }
311 else
312 {
314
317 if (aclresult != ACLCHECK_OK)
320 }
321
322 return restrictionOid;
323}

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

Referenced by AlterOperator(), and DefineOperator().