PostgreSQL Source Code  git master
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;
466  Relation catalog;
467  HeapTuple tup;
468  Form_pg_operator oprForm;
469  int i;
470  ListCell *pl;
471  Datum values[Natts_pg_operator];
472  bool nulls[Natts_pg_operator];
473  bool replaces[Natts_pg_operator];
474  List *restrictionName = NIL; /* optional restrict. sel. function */
475  bool updateRestriction = false;
476  Oid restrictionOid;
477  List *joinName = NIL; /* optional join sel. function */
478  bool updateJoin = false;
479  Oid joinOid;
480  List *commutatorName = NIL; /* optional commutator operator name */
481  Oid commutatorOid;
482  List *negatorName = NIL; /* optional negator operator name */
483  Oid negatorOid;
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);
491  catalog = table_open(OperatorRelationId, RowExclusiveLock);
492  tup = SearchSysCacheCopy1(OPEROID, ObjectIdGetDatum(oprId));
493  if (!HeapTupleIsValid(tup))
494  elog(ERROR, "cache lookup failed for operator %u", oprId);
495  oprForm = (Form_pg_operator) GETSTRUCT(tup);
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  {
520  commutatorName = defGetQualifiedName(defel);
521  }
522  else if (strcmp(defel->defname, "negator") == 0)
523  {
524  negatorName = defGetQualifiedName(defel);
525  }
526  else if (strcmp(defel->defname, "merges") == 0)
527  {
528  canMerge = defGetBoolean(defel);
529  updateMerges = true;
530  }
531  else if (strcmp(defel->defname, "hashes") == 0)
532  {
533  canHash = defGetBoolean(defel);
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  {
546  ereport(ERROR,
547  (errcode(ERRCODE_SYNTAX_ERROR),
548  errmsg("operator attribute \"%s\" cannot be changed",
549  defel->defname)));
550  }
551  else
552  ereport(ERROR,
553  (errcode(ERRCODE_SYNTAX_ERROR),
554  errmsg("operator attribute \"%s\" not recognized",
555  defel->defname)));
556  }
557 
558  /* Check permissions. Must be owner. */
559  if (!object_ownercheck(OperatorRelationId, oprId, GetUserId()))
561  NameStr(oprForm->oprname));
562 
563  /*
564  * Look up OIDs for any parameters specified
565  */
566  if (restrictionName)
567  restrictionOid = ValidateRestrictionEstimator(restrictionName);
568  else
569  restrictionOid = InvalidOid;
570  if (joinName)
571  joinOid = ValidateJoinEstimator(joinName);
572  else
573  joinOid = InvalidOid;
574 
575  if (commutatorName)
576  {
577  /* commutator has reversed arg types */
578  commutatorOid = ValidateOperatorReference(commutatorName,
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
588  commutatorOid = InvalidOid;
589 
590  if (negatorName)
591  {
592  negatorOid = ValidateOperatorReference(negatorName,
593  oprForm->oprleft,
594  oprForm->oprright);
595 
596  /* Must reject self-negation */
597  if (negatorOid == oprForm->oid)
598  ereport(ERROR,
599  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
600  errmsg("operator cannot be its own negator")));
601  }
602  else
603  {
604  negatorOid = InvalidOid;
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)
613  ereport(ERROR,
614  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
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)
620  ereport(ERROR,
621  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
622  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
623  "negator")));
624 
625  if (updateMerges && oprForm->oprcanmerge && !canMerge)
626  ereport(ERROR,
627  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
628  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
629  "merges")));
630 
631  if (updateHashes && oprForm->oprcanhash && !canHash)
632  ereport(ERROR,
633  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
634  errmsg("operator attribute \"%s\" cannot be changed if it has already been set",
635  "hashes")));
636 
637  /* Perform additional checks, like OperatorCreate does */
638  OperatorValidateParams(oprForm->oprleft,
639  oprForm->oprright,
640  oprForm->oprresult,
641  OidIsValid(commutatorOid),
642  OidIsValid(negatorOid),
643  OidIsValid(restrictionOid),
644  OidIsValid(joinOid),
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  }
655  if (updateRestriction)
656  {
657  replaces[Anum_pg_operator_oprrest - 1] = true;
658  values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restrictionOid);
659  }
660  if (updateJoin)
661  {
662  replaces[Anum_pg_operator_oprjoin - 1] = true;
663  values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
664  }
665  if (OidIsValid(commutatorOid))
666  {
667  replaces[Anum_pg_operator_oprcom - 1] = true;
668  values[Anum_pg_operator_oprcom - 1] = ObjectIdGetDatum(commutatorOid);
669  }
670  if (OidIsValid(negatorOid))
671  {
672  replaces[Anum_pg_operator_oprnegate - 1] = true;
673  values[Anum_pg_operator_oprnegate - 1] = ObjectIdGetDatum(negatorOid);
674  }
675  if (updateMerges)
676  {
677  replaces[Anum_pg_operator_oprcanmerge - 1] = true;
678  values[Anum_pg_operator_oprcanmerge - 1] = BoolGetDatum(canMerge);
679  }
680  if (updateHashes)
681  {
682  replaces[Anum_pg_operator_oprcanhash - 1] = true;
683  values[Anum_pg_operator_oprcanhash - 1] = BoolGetDatum(canHash);
684  }
685 
686  tup = heap_modify_tuple(tup, RelationGetDescr(catalog),
687  values, nulls, replaces);
688 
689  CatalogTupleUpdate(catalog, &tup->t_self, tup);
690 
691  address = makeOperatorDependencies(tup, false, true);
692 
693  if (OidIsValid(commutatorOid) || OidIsValid(negatorOid))
694  OperatorUpd(oprId, commutatorOid, negatorOid, false);
695 
696  InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
697 
698  table_close(catalog, NoLock);
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:2688
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4130
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define NameStr(name)
Definition: c.h:746
#define OidIsValid(objectId)
Definition: c.h:775
bool defGetBoolean(DefElem *def)
Definition: define.c:107
List * defGetQualifiedName(DefElem *def)
Definition: define.c:252
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
int i
Definition: isn.c:73
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid GetUserId(void)
Definition: miscinit.c:514
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
static Oid ValidateJoinEstimator(List *joinName)
Definition: operatorcmds.c:310
static Oid ValidateOperatorReference(List *name, Oid leftTypeId, Oid rightTypeId)
Definition: operatorcmds.c:372
static Oid ValidateRestrictionEstimator(List *restrictionName)
Definition: operatorcmds.c:275
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:133
@ OBJECT_OPERATOR
Definition: parsenodes.h:2288
#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)
Definition: pg_operator.c:556
ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool makeExtensionDep, bool isUpdate)
Definition: pg_operator.c:853
void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
Definition: pg_operator.c:684
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:83
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:531
char * defname
Definition: parsenodes.h:815
Node * arg
Definition: parsenodes.h:816
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:86
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, DefElem::arg, BoolGetDatum(), CatalogTupleUpdate(), defGetBoolean(), defGetQualifiedName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, 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, HeapTupleData::t_self, 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;
70  Oid oprNamespace;
71  AclResult aclresult;
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 */
78  Oid typeId2 = InvalidOid;
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 */
85  Oid restrictionOid;
86  Oid joinOid;
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 */
92  oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);
93 
94  /* Check we have creation rights in target namespace */
95  aclresult = object_aclcheck(NamespaceRelationId, oprNamespace, GetUserId(), ACL_CREATE);
96  if (aclresult != ACLCHECK_OK)
97  aclcheck_error(aclresult, OBJECT_SCHEMA,
98  get_namespace_name(oprNamespace));
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  {
109  typeName1 = defGetTypeName(defel);
110  if (typeName1->setof)
111  ereport(ERROR,
112  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
113  errmsg("SETOF type not allowed for operator argument")));
114  }
115  else if (strcmp(defel->defname, "rightarg") == 0)
116  {
117  typeName2 = defGetTypeName(defel);
118  if (typeName2->setof)
119  ereport(ERROR,
120  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
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)
125  functionName = defGetQualifiedName(defel);
126  else if (strcmp(defel->defname, "procedure") == 0)
127  functionName = defGetQualifiedName(defel);
128  else if (strcmp(defel->defname, "commutator") == 0)
129  commutatorName = defGetQualifiedName(defel);
130  else if (strcmp(defel->defname, "negator") == 0)
131  negatorName = defGetQualifiedName(defel);
132  else if (strcmp(defel->defname, "restrict") == 0)
133  restrictionName = defGetQualifiedName(defel);
134  else if (strcmp(defel->defname, "join") == 0)
135  joinName = defGetQualifiedName(defel);
136  else if (strcmp(defel->defname, "hashes") == 0)
137  canHash = defGetBoolean(defel);
138  else if (strcmp(defel->defname, "merges") == 0)
139  canMerge = defGetBoolean(defel);
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 */
153  (errcode(ERRCODE_SYNTAX_ERROR),
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)
163  ereport(ERROR,
164  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
165  errmsg("operator function must be specified")));
166 
167  /* Transform type names to type OIDs */
168  if (typeName1)
169  typeId1 = typenameTypeId(NULL, typeName1);
170  if (typeName2)
171  typeId2 = typenameTypeId(NULL, 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  */
180  if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
181  ereport(ERROR,
182  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
183  errmsg("operator argument types must be specified")));
184  if (!OidIsValid(typeId2))
185  ereport(ERROR,
186  (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
187  errmsg("operator right argument type must be specified"),
188  errdetail("Postfix operators are not supported.")));
189 
190  if (typeName1)
191  {
192  aclresult = object_aclcheck(TypeRelationId, typeId1, GetUserId(), ACL_USAGE);
193  if (aclresult != ACLCHECK_OK)
194  aclcheck_error_type(aclresult, typeId1);
195  }
196 
197  if (typeName2)
198  {
199  aclresult = object_aclcheck(TypeRelationId, typeId2, GetUserId(), ACL_USAGE);
200  if (aclresult != ACLCHECK_OK)
201  aclcheck_error_type(aclresult, typeId2);
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  */
230  aclresult = object_aclcheck(ProcedureRelationId, functionOid, GetUserId(), ACL_EXECUTE);
231  if (aclresult != ACLCHECK_OK)
232  aclcheck_error(aclresult, OBJECT_FUNCTION,
233  NameListToString(functionName));
234 
235  rettype = get_func_rettype(functionOid);
236  aclresult = object_aclcheck(TypeRelationId, rettype, GetUserId(), ACL_USAGE);
237  if (aclresult != ACLCHECK_OK)
238  aclcheck_error_type(aclresult, rettype);
239 
240  /*
241  * Look up restriction and join estimators if specified
242  */
243  if (restrictionName)
244  restrictionOid = ValidateRestrictionEstimator(restrictionName);
245  else
246  restrictionOid = InvalidOid;
247  if (joinName)
248  joinOid = ValidateJoinEstimator(joinName);
249  else
250  joinOid = InvalidOid;
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:3876
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3007
TypeName * defGetTypeName(DefElem *def)
Definition: define.c:284
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define WARNING
Definition: elog.h:36
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
Oid QualifiedNameGetCreationNamespace(const List *names, char **objname_p)
Definition: namespace.c:3472
char * NameListToString(const List *names)
Definition: namespace.c:3579
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2143
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291
#define ACL_USAGE
Definition: parsenodes.h:84
@ OBJECT_SCHEMA
Definition: parsenodes.h:2299
@ OBJECT_FUNCTION
Definition: parsenodes.h:2282
#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)
Definition: pg_operator.c:321
bool setof
Definition: parsenodes.h:270

References ACL_CREATE, ACL_EXECUTE, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, get_func_rettype(), get_namespace_name(), GetUserId(), InvalidOid, lfirst, LookupFuncName(), NameListToString(), NIL, object_aclcheck(), OBJECT_FUNCTION, OBJECT_SCHEMA, OidIsValid, OperatorCreate(), QualifiedNameGetCreationNamespace(), TypeName::setof, 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;
416  HeapTuple tup;
417  Form_pg_operator op;
418 
419  relation = table_open(OperatorRelationId, RowExclusiveLock);
420 
421  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
422  if (!HeapTupleIsValid(tup)) /* should not happen */
423  elog(ERROR, "cache lookup failed for operator %u", operOid);
424  op = (Form_pg_operator) GETSTRUCT(tup);
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  {
437  ReleaseSysCache(tup);
438  tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
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 
446  ReleaseSysCache(tup);
447 
448  table_close(relation, RowExclusiveLock);
449 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:365
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

References CatalogTupleDelete(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, ObjectIdGetDatum(), OidIsValid, OperatorUpd(), ReleaseSysCache(), RowExclusiveLock, SearchSysCache1(), HeapTupleData::t_self, 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;
314  Oid joinOid2;
315  AclResult aclresult;
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))
333  ereport(ERROR,
334  (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
335  errmsg("join estimator function %s has multiple matches",
336  NameListToString(joinName))));
337  }
338  else
339  {
340  joinOid = joinOid2;
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 */
347  if (get_func_rettype(joinOid) != FLOAT8OID)
348  ereport(ERROR,
349  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
350  errmsg("join estimator function %s must return type %s",
351  NameListToString(joinName), "float8")));
352 
353  /* Require EXECUTE rights for the estimator */
354  aclresult = object_aclcheck(ProcedureRelationId, joinOid, GetUserId(), ACL_EXECUTE);
355  if (aclresult != ACLCHECK_OK)
356  aclcheck_error(aclresult, OBJECT_FUNCTION,
357  NameListToString(joinName));
358 
359  return joinOid;
360 }

References ACL_EXECUTE, aclcheck_error(), ACLCHECK_OK, ereport, errcode(), errmsg(), ERROR, 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,
380  leftTypeId,
381  rightTypeId,
382  &defined);
383 
384  /* These message strings are chosen to match parse_oper.c */
385  if (!OidIsValid(oid))
386  ereport(ERROR,
387  (errcode(ERRCODE_UNDEFINED_FUNCTION),
388  errmsg("operator does not exist: %s",
390  leftTypeId,
391  rightTypeId))));
392 
393  if (!defined)
394  ereport(ERROR,
395  (errcode(ERRCODE_UNDEFINED_FUNCTION),
396  errmsg("operator is only a shell: %s",
398  leftTypeId,
399  rightTypeId))));
400 
401  if (!object_ownercheck(OperatorRelationId, oid, GetUserId()))
404 
405  return oid;
406 }
const char * op_signature_string(List *op, Oid arg1, Oid arg2)
Definition: parse_oper.c:602
Oid OperatorLookup(List *operatorName, Oid leftObjectId, Oid rightObjectId, bool *defined)
Definition: pg_operator.c:164
const char * name

References aclcheck_error(), ACLCHECK_NOT_OWNER, ereport, errcode(), errmsg(), ERROR, 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];
278  Oid restrictionOid;
279  AclResult aclresult;
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 */
289  if (get_func_rettype(restrictionOid) != FLOAT8OID)
290  ereport(ERROR,
291  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
292  errmsg("restriction estimator function %s must return type %s",
293  NameListToString(restrictionName), "float8")));
294 
295  /* Require EXECUTE rights for the estimator */
296  aclresult = object_aclcheck(ProcedureRelationId, restrictionOid, GetUserId(), ACL_EXECUTE);
297  if (aclresult != ACLCHECK_OK)
298  aclcheck_error(aclresult, OBJECT_FUNCTION,
299  NameListToString(restrictionName));
300 
301  return restrictionOid;
302 }

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

Referenced by AlterOperator(), and DefineOperator().