PostgreSQL Source Code  git master
opclasscmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * opclasscmds.c
4  *
5  * Routines for opclass (and opfamily) manipulation commands
6  *
7  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/backend/commands/opclasscmds.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include <limits.h>
19 
20 #include "access/genam.h"
21 #include "access/hash.h"
22 #include "access/nbtree.h"
23 #include "access/htup_details.h"
24 #include "access/sysattr.h"
25 #include "access/table.h"
26 #include "catalog/catalog.h"
27 #include "catalog/dependency.h"
28 #include "catalog/indexing.h"
29 #include "catalog/objectaccess.h"
30 #include "catalog/opfam_internal.h"
31 #include "catalog/pg_am.h"
32 #include "catalog/pg_amop.h"
33 #include "catalog/pg_amproc.h"
34 #include "catalog/pg_namespace.h"
35 #include "catalog/pg_opclass.h"
36 #include "catalog/pg_operator.h"
37 #include "catalog/pg_opfamily.h"
38 #include "catalog/pg_proc.h"
39 #include "catalog/pg_type.h"
40 #include "commands/alter.h"
41 #include "commands/defrem.h"
42 #include "commands/event_trigger.h"
43 #include "miscadmin.h"
44 #include "parser/parse_func.h"
45 #include "parser/parse_oper.h"
46 #include "parser/parse_type.h"
47 #include "utils/builtins.h"
48 #include "utils/fmgroids.h"
49 #include "utils/lsyscache.h"
50 #include "utils/rel.h"
51 #include "utils/syscache.h"
52 
53 
54 static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
55  Oid amoid, Oid opfamilyoid,
56  int maxOpNumber, int maxProcNumber,
57  List *items);
58 static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
59  Oid amoid, Oid opfamilyoid,
60  int maxOpNumber, int maxProcNumber,
61  List *items);
62 static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
63 static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
64 static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
65 static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
66 static void storeOperators(List *opfamilyname, Oid amoid,
67  Oid opfamilyoid, Oid opclassoid,
68  List *operators, bool isAdd);
69 static void storeProcedures(List *opfamilyname, Oid amoid,
70  Oid opfamilyoid, Oid opclassoid,
71  List *procedures, bool isAdd);
72 static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
73  List *operators);
74 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
75  List *procedures);
76 
77 /*
78  * OpFamilyCacheLookup
79  * Look up an existing opfamily by name.
80  *
81  * Returns a syscache tuple reference, or NULL if not found.
82  */
83 static HeapTuple
84 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
85 {
86  char *schemaname;
87  char *opfname;
88  HeapTuple htup;
89 
90  /* deconstruct the name list */
91  DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
92 
93  if (schemaname)
94  {
95  /* Look in specific schema only */
96  Oid namespaceId;
97 
98  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
99  if (!OidIsValid(namespaceId))
100  htup = NULL;
101  else
103  ObjectIdGetDatum(amID),
104  PointerGetDatum(opfname),
105  ObjectIdGetDatum(namespaceId));
106  }
107  else
108  {
109  /* Unqualified opfamily name, so search the search path */
110  Oid opfID = OpfamilynameGetOpfid(amID, opfname);
111 
112  if (!OidIsValid(opfID))
113  htup = NULL;
114  else
116  }
117 
118  if (!HeapTupleIsValid(htup) && !missing_ok)
119  {
120  HeapTuple amtup;
121 
122  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
123  if (!HeapTupleIsValid(amtup))
124  elog(ERROR, "cache lookup failed for access method %u", amID);
125  ereport(ERROR,
126  (errcode(ERRCODE_UNDEFINED_OBJECT),
127  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
128  NameListToString(opfamilyname),
129  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
130  }
131 
132  return htup;
133 }
134 
135 /*
136  * get_opfamily_oid
137  * find an opfamily OID by possibly qualified name
138  *
139  * If not found, returns InvalidOid if missing_ok, else throws error.
140  */
141 Oid
142 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
143 {
144  HeapTuple htup;
145  Form_pg_opfamily opfamform;
146  Oid opfID;
147 
148  htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
149  if (!HeapTupleIsValid(htup))
150  return InvalidOid;
151  opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
152  opfID = opfamform->oid;
153  ReleaseSysCache(htup);
154 
155  return opfID;
156 }
157 
158 /*
159  * OpClassCacheLookup
160  * Look up an existing opclass by name.
161  *
162  * Returns a syscache tuple reference, or NULL if not found.
163  */
164 static HeapTuple
165 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
166 {
167  char *schemaname;
168  char *opcname;
169  HeapTuple htup;
170 
171  /* deconstruct the name list */
172  DeconstructQualifiedName(opclassname, &schemaname, &opcname);
173 
174  if (schemaname)
175  {
176  /* Look in specific schema only */
177  Oid namespaceId;
178 
179  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180  if (!OidIsValid(namespaceId))
181  htup = NULL;
182  else
184  ObjectIdGetDatum(amID),
185  PointerGetDatum(opcname),
186  ObjectIdGetDatum(namespaceId));
187  }
188  else
189  {
190  /* Unqualified opclass name, so search the search path */
191  Oid opcID = OpclassnameGetOpcid(amID, opcname);
192 
193  if (!OidIsValid(opcID))
194  htup = NULL;
195  else
196  htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
197  }
198 
199  if (!HeapTupleIsValid(htup) && !missing_ok)
200  {
201  HeapTuple amtup;
202 
203  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
204  if (!HeapTupleIsValid(amtup))
205  elog(ERROR, "cache lookup failed for access method %u", amID);
206  ereport(ERROR,
207  (errcode(ERRCODE_UNDEFINED_OBJECT),
208  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
209  NameListToString(opclassname),
210  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
211  }
212 
213  return htup;
214 }
215 
216 /*
217  * get_opclass_oid
218  * find an opclass OID by possibly qualified name
219  *
220  * If not found, returns InvalidOid if missing_ok, else throws error.
221  */
222 Oid
223 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
224 {
225  HeapTuple htup;
226  Form_pg_opclass opcform;
227  Oid opcID;
228 
229  htup = OpClassCacheLookup(amID, opclassname, missing_ok);
230  if (!HeapTupleIsValid(htup))
231  return InvalidOid;
232  opcform = (Form_pg_opclass) GETSTRUCT(htup);
233  opcID = opcform->oid;
234  ReleaseSysCache(htup);
235 
236  return opcID;
237 }
238 
239 /*
240  * CreateOpFamily
241  * Internal routine to make the catalog entry for a new operator family.
242  *
243  * Caller must have done permissions checks etc. already.
244  */
245 static ObjectAddress
246 CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
247 {
248  Oid opfamilyoid;
249  Relation rel;
250  HeapTuple tup;
251  Datum values[Natts_pg_opfamily];
252  bool nulls[Natts_pg_opfamily];
253  NameData opfName;
254  ObjectAddress myself,
255  referenced;
256 
257  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
258 
259  /*
260  * Make sure there is no existing opfamily of this name (this is just to
261  * give a more friendly error message than "duplicate key").
262  */
264  ObjectIdGetDatum(amoid),
265  CStringGetDatum(opfname),
266  ObjectIdGetDatum(namespaceoid)))
267  ereport(ERROR,
269  errmsg("operator family \"%s\" for access method \"%s\" already exists",
270  opfname, amname)));
271 
272  /*
273  * Okay, let's create the pg_opfamily entry.
274  */
275  memset(values, 0, sizeof(values));
276  memset(nulls, false, sizeof(nulls));
277 
278  opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
279  Anum_pg_opfamily_oid);
280  values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
281  values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
282  namestrcpy(&opfName, opfname);
283  values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
284  values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
285  values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
286 
287  tup = heap_form_tuple(rel->rd_att, values, nulls);
288 
289  CatalogTupleInsert(rel, tup);
290 
291  heap_freetuple(tup);
292 
293  /*
294  * Create dependencies for the opfamily proper.
295  */
296  myself.classId = OperatorFamilyRelationId;
297  myself.objectId = opfamilyoid;
298  myself.objectSubId = 0;
299 
300  /* dependency on access method */
301  referenced.classId = AccessMethodRelationId;
302  referenced.objectId = amoid;
303  referenced.objectSubId = 0;
304  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
305 
306  /* dependency on namespace */
307  referenced.classId = NamespaceRelationId;
308  referenced.objectId = namespaceoid;
309  referenced.objectSubId = 0;
310  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
311 
312  /* dependency on owner */
313  recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
314 
315  /* dependency on extension */
316  recordDependencyOnCurrentExtension(&myself, false);
317 
318  /* Post creation hook for new operator family */
319  InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
320 
322 
323  return myself;
324 }
325 
326 /*
327  * DefineOpClass
328  * Define a new index operator class.
329  */
332 {
333  char *opcname; /* name of opclass we're creating */
334  Oid amoid, /* our AM's oid */
335  typeoid, /* indexable datatype oid */
336  storageoid, /* storage datatype oid, if any */
337  namespaceoid, /* namespace to create opclass in */
338  opfamilyoid, /* oid of containing opfamily */
339  opclassoid; /* oid of opclass we create */
340  int maxOpNumber, /* amstrategies value */
341  maxProcNumber; /* amsupport value */
342  bool amstorage; /* amstorage flag */
343  List *operators; /* OpFamilyMember list for operators */
344  List *procedures; /* OpFamilyMember list for support procs */
345  ListCell *l;
346  Relation rel;
347  HeapTuple tup;
348  Form_pg_am amform;
349  IndexAmRoutine *amroutine;
350  Datum values[Natts_pg_opclass];
351  bool nulls[Natts_pg_opclass];
352  AclResult aclresult;
353  NameData opcName;
354  ObjectAddress myself,
355  referenced;
356 
357  /* Convert list of names to a name and namespace */
358  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
359  &opcname);
360 
361  /* Check we have creation rights in target namespace */
362  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
363  if (aclresult != ACLCHECK_OK)
364  aclcheck_error(aclresult, OBJECT_SCHEMA,
365  get_namespace_name(namespaceoid));
366 
367  /* Get necessary info about access method */
369  if (!HeapTupleIsValid(tup))
370  ereport(ERROR,
371  (errcode(ERRCODE_UNDEFINED_OBJECT),
372  errmsg("access method \"%s\" does not exist",
373  stmt->amname)));
374 
375  amform = (Form_pg_am) GETSTRUCT(tup);
376  amoid = amform->oid;
377  amroutine = GetIndexAmRoutineByAmId(amoid, false);
378  ReleaseSysCache(tup);
379 
380  maxOpNumber = amroutine->amstrategies;
381  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
382  if (maxOpNumber <= 0)
383  maxOpNumber = SHRT_MAX;
384  maxProcNumber = amroutine->amsupport;
385  amstorage = amroutine->amstorage;
386 
387  /* XXX Should we make any privilege check against the AM? */
388 
389  /*
390  * The question of appropriate permissions for CREATE OPERATOR CLASS is
391  * interesting. Creating an opclass is tantamount to granting public
392  * execute access on the functions involved, since the index machinery
393  * generally does not check access permission before using the functions.
394  * A minimum expectation therefore is that the caller have execute
395  * privilege with grant option. Since we don't have a way to make the
396  * opclass go away if the grant option is revoked, we choose instead to
397  * require ownership of the functions. It's also not entirely clear what
398  * permissions should be required on the datatype, but ownership seems
399  * like a safe choice.
400  *
401  * Currently, we require superuser privileges to create an opclass. This
402  * seems necessary because we have no way to validate that the offered set
403  * of operators and functions are consistent with the AM's expectations.
404  * It would be nice to provide such a check someday, if it can be done
405  * without solving the halting problem :-(
406  *
407  * XXX re-enable NOT_USED code sections below if you remove this test.
408  */
409  if (!superuser())
410  ereport(ERROR,
411  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
412  errmsg("must be superuser to create an operator class")));
413 
414  /* Look up the datatype */
415  typeoid = typenameTypeId(NULL, stmt->datatype);
416 
417 #ifdef NOT_USED
418  /* XXX this is unnecessary given the superuser check above */
419  /* Check we have ownership of the datatype */
420  if (!pg_type_ownercheck(typeoid, GetUserId()))
422 #endif
423 
424  /*
425  * Look up the containing operator family, or create one if FAMILY option
426  * was omitted and there's not a match already.
427  */
428  if (stmt->opfamilyname)
429  {
430  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
431  }
432  else
433  {
434  /* Lookup existing family of same name and namespace */
436  ObjectIdGetDatum(amoid),
437  PointerGetDatum(opcname),
438  ObjectIdGetDatum(namespaceoid));
439  if (HeapTupleIsValid(tup))
440  {
441  opfamilyoid = ((Form_pg_opfamily) GETSTRUCT(tup))->oid;
442 
443  /*
444  * XXX given the superuser check above, there's no need for an
445  * ownership check here
446  */
447  ReleaseSysCache(tup);
448  }
449  else
450  {
451  ObjectAddress tmpAddr;
452 
453  /*
454  * Create it ... again no need for more permissions ...
455  */
456  tmpAddr = CreateOpFamily(stmt->amname, opcname,
457  namespaceoid, amoid);
458  opfamilyoid = tmpAddr.objectId;
459  }
460  }
461 
462  operators = NIL;
463  procedures = NIL;
464 
465  /* Storage datatype is optional */
466  storageoid = InvalidOid;
467 
468  /*
469  * Scan the "items" list to obtain additional info.
470  */
471  foreach(l, stmt->items)
472  {
474  Oid operOid;
475  Oid funcOid;
476  Oid sortfamilyOid;
478 
479  switch (item->itemtype)
480  {
482  if (item->number <= 0 || item->number > maxOpNumber)
483  ereport(ERROR,
484  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
485  errmsg("invalid operator number %d,"
486  " must be between 1 and %d",
487  item->number, maxOpNumber)));
488  if (item->name->objargs != NIL)
489  operOid = LookupOperWithArgs(item->name, false);
490  else
491  {
492  /* Default to binary op on input datatype */
493  operOid = LookupOperName(NULL, item->name->objname,
494  typeoid, typeoid,
495  false, -1);
496  }
497 
498  if (item->order_family)
499  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
500  item->order_family,
501  false);
502  else
503  sortfamilyOid = InvalidOid;
504 
505 #ifdef NOT_USED
506  /* XXX this is unnecessary given the superuser check above */
507  /* Caller must own operator and its underlying function */
508  if (!pg_oper_ownercheck(operOid, GetUserId()))
510  get_opname(operOid));
511  funcOid = get_opcode(operOid);
512  if (!pg_proc_ownercheck(funcOid, GetUserId()))
514  get_func_name(funcOid));
515 #endif
516 
517  /* Save the info */
518  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
519  member->object = operOid;
520  member->number = item->number;
521  member->sortfamily = sortfamilyOid;
522  assignOperTypes(member, amoid, typeoid);
523  addFamilyMember(&operators, member, false);
524  break;
526  if (item->number <= 0 || item->number > maxProcNumber)
527  ereport(ERROR,
528  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
529  errmsg("invalid function number %d,"
530  " must be between 1 and %d",
531  item->number, maxProcNumber)));
532  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
533 #ifdef NOT_USED
534  /* XXX this is unnecessary given the superuser check above */
535  /* Caller must own function */
536  if (!pg_proc_ownercheck(funcOid, GetUserId()))
538  get_func_name(funcOid));
539 #endif
540 
541  /* Save the info */
542  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
543  member->object = funcOid;
544  member->number = item->number;
545 
546  /* allow overriding of the function's actual arg types */
547  if (item->class_args)
549  &member->lefttype, &member->righttype);
550 
551  assignProcTypes(member, amoid, typeoid);
552  addFamilyMember(&procedures, member, true);
553  break;
555  if (OidIsValid(storageoid))
556  ereport(ERROR,
557  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
558  errmsg("storage type specified more than once")));
559  storageoid = typenameTypeId(NULL, item->storedtype);
560 
561 #ifdef NOT_USED
562  /* XXX this is unnecessary given the superuser check above */
563  /* Check we have ownership of the datatype */
564  if (!pg_type_ownercheck(storageoid, GetUserId()))
566 #endif
567  break;
568  default:
569  elog(ERROR, "unrecognized item type: %d", item->itemtype);
570  break;
571  }
572  }
573 
574  /*
575  * If storagetype is specified, make sure it's legal.
576  */
577  if (OidIsValid(storageoid))
578  {
579  /* Just drop the spec if same as column datatype */
580  if (storageoid == typeoid)
581  storageoid = InvalidOid;
582  else if (!amstorage)
583  ereport(ERROR,
584  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
585  errmsg("storage type cannot be different from data type for access method \"%s\"",
586  stmt->amname)));
587  }
588 
589  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
590 
591  /*
592  * Make sure there is no existing opclass of this name (this is just to
593  * give a more friendly error message than "duplicate key").
594  */
596  ObjectIdGetDatum(amoid),
597  CStringGetDatum(opcname),
598  ObjectIdGetDatum(namespaceoid)))
599  ereport(ERROR,
601  errmsg("operator class \"%s\" for access method \"%s\" already exists",
602  opcname, stmt->amname)));
603 
604  /*
605  * If we are creating a default opclass, check there isn't one already.
606  * (Note we do not restrict this test to visible opclasses; this ensures
607  * that typcache.c can find unique solutions to its questions.)
608  */
609  if (stmt->isDefault)
610  {
611  ScanKeyData skey[1];
612  SysScanDesc scan;
613 
614  ScanKeyInit(&skey[0],
615  Anum_pg_opclass_opcmethod,
616  BTEqualStrategyNumber, F_OIDEQ,
617  ObjectIdGetDatum(amoid));
618 
620  NULL, 1, skey);
621 
622  while (HeapTupleIsValid(tup = systable_getnext(scan)))
623  {
624  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
625 
626  if (opclass->opcintype == typeoid && opclass->opcdefault)
627  ereport(ERROR,
629  errmsg("could not make operator class \"%s\" be default for type %s",
630  opcname,
631  TypeNameToString(stmt->datatype)),
632  errdetail("Operator class \"%s\" already is the default.",
633  NameStr(opclass->opcname))));
634  }
635 
636  systable_endscan(scan);
637  }
638 
639  /*
640  * Okay, let's create the pg_opclass entry.
641  */
642  memset(values, 0, sizeof(values));
643  memset(nulls, false, sizeof(nulls));
644 
645  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
646  Anum_pg_opclass_oid);
647  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
648  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
649  namestrcpy(&opcName, opcname);
650  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
651  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
652  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
653  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
654  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
655  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
656  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
657 
658  tup = heap_form_tuple(rel->rd_att, values, nulls);
659 
660  CatalogTupleInsert(rel, tup);
661 
662  heap_freetuple(tup);
663 
664  /*
665  * Now add tuples to pg_amop and pg_amproc tying in the operators and
666  * functions. Dependencies on them are inserted, too.
667  */
668  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
669  opclassoid, operators, false);
670  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
671  opclassoid, procedures, false);
672 
673  /* let event triggers know what happened */
674  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
675 
676  /*
677  * Create dependencies for the opclass proper. Note: we do not need a
678  * dependency link to the AM, because that exists through the opfamily.
679  */
680  myself.classId = OperatorClassRelationId;
681  myself.objectId = opclassoid;
682  myself.objectSubId = 0;
683 
684  /* dependency on namespace */
685  referenced.classId = NamespaceRelationId;
686  referenced.objectId = namespaceoid;
687  referenced.objectSubId = 0;
688  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
689 
690  /* dependency on opfamily */
691  referenced.classId = OperatorFamilyRelationId;
692  referenced.objectId = opfamilyoid;
693  referenced.objectSubId = 0;
694  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
695 
696  /* dependency on indexed datatype */
697  referenced.classId = TypeRelationId;
698  referenced.objectId = typeoid;
699  referenced.objectSubId = 0;
700  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
701 
702  /* dependency on storage datatype */
703  if (OidIsValid(storageoid))
704  {
705  referenced.classId = TypeRelationId;
706  referenced.objectId = storageoid;
707  referenced.objectSubId = 0;
708  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
709  }
710 
711  /* dependency on owner */
712  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
713 
714  /* dependency on extension */
715  recordDependencyOnCurrentExtension(&myself, false);
716 
717  /* Post creation hook for new operator class */
718  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
719 
721 
722  return myself;
723 }
724 
725 
726 /*
727  * DefineOpFamily
728  * Define a new index operator family.
729  */
732 {
733  char *opfname; /* name of opfamily we're creating */
734  Oid amoid, /* our AM's oid */
735  namespaceoid; /* namespace to create opfamily in */
736  AclResult aclresult;
737 
738  /* Convert list of names to a name and namespace */
739  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
740  &opfname);
741 
742  /* Check we have creation rights in target namespace */
743  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
744  if (aclresult != ACLCHECK_OK)
745  aclcheck_error(aclresult, OBJECT_SCHEMA,
746  get_namespace_name(namespaceoid));
747 
748  /* Get access method OID, throwing an error if it doesn't exist. */
749  amoid = get_index_am_oid(stmt->amname, false);
750 
751  /* XXX Should we make any privilege check against the AM? */
752 
753  /*
754  * Currently, we require superuser privileges to create an opfamily. See
755  * comments in DefineOpClass.
756  */
757  if (!superuser())
758  ereport(ERROR,
759  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
760  errmsg("must be superuser to create an operator family")));
761 
762  /* Insert pg_opfamily catalog entry */
763  return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
764 }
765 
766 
767 /*
768  * AlterOpFamily
769  * Add or remove operators/procedures within an existing operator family.
770  *
771  * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
772  * other commands called ALTER OPERATOR FAMILY exist, but go through
773  * different code paths.
774  */
775 Oid
777 {
778  Oid amoid, /* our AM's oid */
779  opfamilyoid; /* oid of opfamily */
780  int maxOpNumber, /* amstrategies value */
781  maxProcNumber; /* amsupport value */
782  HeapTuple tup;
783  Form_pg_am amform;
784  IndexAmRoutine *amroutine;
785 
786  /* Get necessary info about access method */
788  if (!HeapTupleIsValid(tup))
789  ereport(ERROR,
790  (errcode(ERRCODE_UNDEFINED_OBJECT),
791  errmsg("access method \"%s\" does not exist",
792  stmt->amname)));
793 
794  amform = (Form_pg_am) GETSTRUCT(tup);
795  amoid = amform->oid;
796  amroutine = GetIndexAmRoutineByAmId(amoid, false);
797  ReleaseSysCache(tup);
798 
799  maxOpNumber = amroutine->amstrategies;
800  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
801  if (maxOpNumber <= 0)
802  maxOpNumber = SHRT_MAX;
803  maxProcNumber = amroutine->amsupport;
804 
805  /* XXX Should we make any privilege check against the AM? */
806 
807  /* Look up the opfamily */
808  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
809 
810  /*
811  * Currently, we require superuser privileges to alter an opfamily.
812  *
813  * XXX re-enable NOT_USED code sections below if you remove this test.
814  */
815  if (!superuser())
816  ereport(ERROR,
817  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
818  errmsg("must be superuser to alter an operator family")));
819 
820  /*
821  * ADD and DROP cases need separate code from here on down.
822  */
823  if (stmt->isDrop)
824  AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
825  maxOpNumber, maxProcNumber, stmt->items);
826  else
827  AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
828  maxOpNumber, maxProcNumber, stmt->items);
829 
830  return opfamilyoid;
831 }
832 
833 /*
834  * ADD part of ALTER OP FAMILY
835  */
836 static void
837 AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
838  int maxOpNumber, int maxProcNumber, List *items)
839 {
840  List *operators; /* OpFamilyMember list for operators */
841  List *procedures; /* OpFamilyMember list for support procs */
842  ListCell *l;
843 
844  operators = NIL;
845  procedures = NIL;
846 
847  /*
848  * Scan the "items" list to obtain additional info.
849  */
850  foreach(l, items)
851  {
853  Oid operOid;
854  Oid funcOid;
855  Oid sortfamilyOid;
857 
858  switch (item->itemtype)
859  {
861  if (item->number <= 0 || item->number > maxOpNumber)
862  ereport(ERROR,
863  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
864  errmsg("invalid operator number %d,"
865  " must be between 1 and %d",
866  item->number, maxOpNumber)));
867  if (item->name->objargs != NIL)
868  operOid = LookupOperWithArgs(item->name, false);
869  else
870  {
871  ereport(ERROR,
872  (errcode(ERRCODE_SYNTAX_ERROR),
873  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
874  operOid = InvalidOid; /* keep compiler quiet */
875  }
876 
877  if (item->order_family)
878  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
879  item->order_family,
880  false);
881  else
882  sortfamilyOid = InvalidOid;
883 
884 #ifdef NOT_USED
885  /* XXX this is unnecessary given the superuser check above */
886  /* Caller must own operator and its underlying function */
887  if (!pg_oper_ownercheck(operOid, GetUserId()))
889  get_opname(operOid));
890  funcOid = get_opcode(operOid);
891  if (!pg_proc_ownercheck(funcOid, GetUserId()))
893  get_func_name(funcOid));
894 #endif
895 
896  /* Save the info */
897  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
898  member->object = operOid;
899  member->number = item->number;
900  member->sortfamily = sortfamilyOid;
901  assignOperTypes(member, amoid, InvalidOid);
902  addFamilyMember(&operators, member, false);
903  break;
905  if (item->number <= 0 || item->number > maxProcNumber)
906  ereport(ERROR,
907  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
908  errmsg("invalid function number %d,"
909  " must be between 1 and %d",
910  item->number, maxProcNumber)));
911  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
912 #ifdef NOT_USED
913  /* XXX this is unnecessary given the superuser check above */
914  /* Caller must own function */
915  if (!pg_proc_ownercheck(funcOid, GetUserId()))
917  get_func_name(funcOid));
918 #endif
919 
920  /* Save the info */
921  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
922  member->object = funcOid;
923  member->number = item->number;
924 
925  /* allow overriding of the function's actual arg types */
926  if (item->class_args)
928  &member->lefttype, &member->righttype);
929 
930  assignProcTypes(member, amoid, InvalidOid);
931  addFamilyMember(&procedures, member, true);
932  break;
934  ereport(ERROR,
935  (errcode(ERRCODE_SYNTAX_ERROR),
936  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
937  break;
938  default:
939  elog(ERROR, "unrecognized item type: %d", item->itemtype);
940  break;
941  }
942  }
943 
944  /*
945  * Add tuples to pg_amop and pg_amproc tying in the operators and
946  * functions. Dependencies on them are inserted, too.
947  */
948  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
949  InvalidOid, operators, true);
950  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
951  InvalidOid, procedures, true);
952 
953  /* make information available to event triggers */
954  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
955  operators, procedures);
956 }
957 
958 /*
959  * DROP part of ALTER OP FAMILY
960  */
961 static void
962 AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
963  int maxOpNumber, int maxProcNumber, List *items)
964 {
965  List *operators; /* OpFamilyMember list for operators */
966  List *procedures; /* OpFamilyMember list for support procs */
967  ListCell *l;
968 
969  operators = NIL;
970  procedures = NIL;
971 
972  /*
973  * Scan the "items" list to obtain additional info.
974  */
975  foreach(l, items)
976  {
978  Oid lefttype,
979  righttype;
981 
982  switch (item->itemtype)
983  {
985  if (item->number <= 0 || item->number > maxOpNumber)
986  ereport(ERROR,
987  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
988  errmsg("invalid operator number %d,"
989  " must be between 1 and %d",
990  item->number, maxOpNumber)));
991  processTypesSpec(item->class_args, &lefttype, &righttype);
992  /* Save the info */
993  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
994  member->number = item->number;
995  member->lefttype = lefttype;
996  member->righttype = righttype;
997  addFamilyMember(&operators, member, false);
998  break;
1000  if (item->number <= 0 || item->number > maxProcNumber)
1001  ereport(ERROR,
1002  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1003  errmsg("invalid function number %d,"
1004  " must be between 1 and %d",
1005  item->number, maxProcNumber)));
1006  processTypesSpec(item->class_args, &lefttype, &righttype);
1007  /* Save the info */
1008  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1009  member->number = item->number;
1010  member->lefttype = lefttype;
1011  member->righttype = righttype;
1012  addFamilyMember(&procedures, member, true);
1013  break;
1015  /* grammar prevents this from appearing */
1016  default:
1017  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1018  break;
1019  }
1020  }
1021 
1022  /*
1023  * Remove tuples from pg_amop and pg_amproc.
1024  */
1025  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1026  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1027 
1028  /* make information available to event triggers */
1029  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1030  operators, procedures);
1031 }
1032 
1033 
1034 /*
1035  * Deal with explicit arg types used in ALTER ADD/DROP
1036  */
1037 static void
1038 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1039 {
1040  TypeName *typeName;
1041 
1042  Assert(args != NIL);
1043 
1044  typeName = (TypeName *) linitial(args);
1045  *lefttype = typenameTypeId(NULL, typeName);
1046 
1047  if (list_length(args) > 1)
1048  {
1049  typeName = (TypeName *) lsecond(args);
1050  *righttype = typenameTypeId(NULL, typeName);
1051  }
1052  else
1053  *righttype = *lefttype;
1054 
1055  if (list_length(args) > 2)
1056  ereport(ERROR,
1057  (errcode(ERRCODE_SYNTAX_ERROR),
1058  errmsg("one or two argument types must be specified")));
1059 }
1060 
1061 
1062 /*
1063  * Determine the lefttype/righttype to assign to an operator,
1064  * and do any validity checking we can manage.
1065  */
1066 static void
1068 {
1069  Operator optup;
1070  Form_pg_operator opform;
1071 
1072  /* Fetch the operator definition */
1073  optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1074  if (!HeapTupleIsValid(optup))
1075  elog(ERROR, "cache lookup failed for operator %u", member->object);
1076  opform = (Form_pg_operator) GETSTRUCT(optup);
1077 
1078  /*
1079  * Opfamily operators must be binary.
1080  */
1081  if (opform->oprkind != 'b')
1082  ereport(ERROR,
1083  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1084  errmsg("index operators must be binary")));
1085 
1086  if (OidIsValid(member->sortfamily))
1087  {
1088  /*
1089  * Ordering op, check index supports that. (We could perhaps also
1090  * check that the operator returns a type supported by the sortfamily,
1091  * but that seems more trouble than it's worth here. If it does not,
1092  * the operator will never be matchable to any ORDER BY clause, but no
1093  * worse consequences can ensue. Also, trying to check that would
1094  * create an ordering hazard during dump/reload: it's possible that
1095  * the family has been created but not yet populated with the required
1096  * operators.)
1097  */
1098  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
1099 
1100  if (!amroutine->amcanorderbyop)
1101  ereport(ERROR,
1102  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1103  errmsg("access method \"%s\" does not support ordering operators",
1104  get_am_name(amoid))));
1105  }
1106  else
1107  {
1108  /*
1109  * Search operators must return boolean.
1110  */
1111  if (opform->oprresult != BOOLOID)
1112  ereport(ERROR,
1113  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1114  errmsg("index search operators must return boolean")));
1115  }
1116 
1117  /*
1118  * If lefttype/righttype isn't specified, use the operator's input types
1119  */
1120  if (!OidIsValid(member->lefttype))
1121  member->lefttype = opform->oprleft;
1122  if (!OidIsValid(member->righttype))
1123  member->righttype = opform->oprright;
1124 
1125  ReleaseSysCache(optup);
1126 }
1127 
1128 /*
1129  * Determine the lefttype/righttype to assign to a support procedure,
1130  * and do any validity checking we can manage.
1131  */
1132 static void
1134 {
1135  HeapTuple proctup;
1136  Form_pg_proc procform;
1137 
1138  /* Fetch the procedure definition */
1139  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1140  if (!HeapTupleIsValid(proctup))
1141  elog(ERROR, "cache lookup failed for function %u", member->object);
1142  procform = (Form_pg_proc) GETSTRUCT(proctup);
1143 
1144  /*
1145  * btree comparison procs must be 2-arg procs returning int4. btree
1146  * sortsupport procs must take internal and return void. btree in_range
1147  * procs must be 5-arg procs returning bool. hash support proc 1 must be
1148  * a 1-arg proc returning int4, while proc 2 must be a 2-arg proc
1149  * returning int8. Otherwise we don't know.
1150  */
1151  if (amoid == BTREE_AM_OID)
1152  {
1153  if (member->number == BTORDER_PROC)
1154  {
1155  if (procform->pronargs != 2)
1156  ereport(ERROR,
1157  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1158  errmsg("btree comparison functions must have two arguments")));
1159  if (procform->prorettype != INT4OID)
1160  ereport(ERROR,
1161  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1162  errmsg("btree comparison functions must return integer")));
1163 
1164  /*
1165  * If lefttype/righttype isn't specified, use the proc's input
1166  * types
1167  */
1168  if (!OidIsValid(member->lefttype))
1169  member->lefttype = procform->proargtypes.values[0];
1170  if (!OidIsValid(member->righttype))
1171  member->righttype = procform->proargtypes.values[1];
1172  }
1173  else if (member->number == BTSORTSUPPORT_PROC)
1174  {
1175  if (procform->pronargs != 1 ||
1176  procform->proargtypes.values[0] != INTERNALOID)
1177  ereport(ERROR,
1178  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1179  errmsg("btree sort support functions must accept type \"internal\"")));
1180  if (procform->prorettype != VOIDOID)
1181  ereport(ERROR,
1182  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1183  errmsg("btree sort support functions must return void")));
1184 
1185  /*
1186  * Can't infer lefttype/righttype from proc, so use default rule
1187  */
1188  }
1189  else if (member->number == BTINRANGE_PROC)
1190  {
1191  if (procform->pronargs != 5)
1192  ereport(ERROR,
1193  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1194  errmsg("btree in_range functions must have five arguments")));
1195  if (procform->prorettype != BOOLOID)
1196  ereport(ERROR,
1197  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1198  errmsg("btree in_range functions must return boolean")));
1199 
1200  /*
1201  * If lefttype/righttype isn't specified, use the proc's input
1202  * types (we look at the test-value and offset arguments)
1203  */
1204  if (!OidIsValid(member->lefttype))
1205  member->lefttype = procform->proargtypes.values[0];
1206  if (!OidIsValid(member->righttype))
1207  member->righttype = procform->proargtypes.values[2];
1208  }
1209  }
1210  else if (amoid == HASH_AM_OID)
1211  {
1212  if (member->number == HASHSTANDARD_PROC)
1213  {
1214  if (procform->pronargs != 1)
1215  ereport(ERROR,
1216  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1217  errmsg("hash function 1 must have one argument")));
1218  if (procform->prorettype != INT4OID)
1219  ereport(ERROR,
1220  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1221  errmsg("hash function 1 must return integer")));
1222  }
1223  else if (member->number == HASHEXTENDED_PROC)
1224  {
1225  if (procform->pronargs != 2)
1226  ereport(ERROR,
1227  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1228  errmsg("hash function 2 must have two arguments")));
1229  if (procform->prorettype != INT8OID)
1230  ereport(ERROR,
1231  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1232  errmsg("hash function 2 must return bigint")));
1233  }
1234 
1235  /*
1236  * If lefttype/righttype isn't specified, use the proc's input type
1237  */
1238  if (!OidIsValid(member->lefttype))
1239  member->lefttype = procform->proargtypes.values[0];
1240  if (!OidIsValid(member->righttype))
1241  member->righttype = procform->proargtypes.values[0];
1242  }
1243 
1244  /*
1245  * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1246  * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1247  * isn't available, so make the user specify the types.
1248  */
1249  if (!OidIsValid(member->lefttype))
1250  member->lefttype = typeoid;
1251  if (!OidIsValid(member->righttype))
1252  member->righttype = typeoid;
1253 
1254  if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1255  ereport(ERROR,
1256  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1257  errmsg("associated data types must be specified for index support function")));
1258 
1259  ReleaseSysCache(proctup);
1260 }
1261 
1262 /*
1263  * Add a new family member to the appropriate list, after checking for
1264  * duplicated strategy or proc number.
1265  */
1266 static void
1268 {
1269  ListCell *l;
1270 
1271  foreach(l, *list)
1272  {
1273  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1274 
1275  if (old->number == member->number &&
1276  old->lefttype == member->lefttype &&
1277  old->righttype == member->righttype)
1278  {
1279  if (isProc)
1280  ereport(ERROR,
1281  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1282  errmsg("function number %d for (%s,%s) appears more than once",
1283  member->number,
1284  format_type_be(member->lefttype),
1285  format_type_be(member->righttype))));
1286  else
1287  ereport(ERROR,
1288  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1289  errmsg("operator number %d for (%s,%s) appears more than once",
1290  member->number,
1291  format_type_be(member->lefttype),
1292  format_type_be(member->righttype))));
1293  }
1294  }
1295  *list = lappend(*list, member);
1296 }
1297 
1298 /*
1299  * Dump the operators to pg_amop
1300  *
1301  * We also make dependency entries in pg_depend for the opfamily entries.
1302  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1303  * else make an AUTO dependency on the opfamily.
1304  */
1305 static void
1306 storeOperators(List *opfamilyname, Oid amoid,
1307  Oid opfamilyoid, Oid opclassoid,
1308  List *operators, bool isAdd)
1309 {
1310  Relation rel;
1311  Datum values[Natts_pg_amop];
1312  bool nulls[Natts_pg_amop];
1313  HeapTuple tup;
1314  Oid entryoid;
1315  ObjectAddress myself,
1316  referenced;
1317  ListCell *l;
1318 
1319  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1320 
1321  foreach(l, operators)
1322  {
1323  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1324  char oppurpose;
1325 
1326  /*
1327  * If adding to an existing family, check for conflict with an
1328  * existing pg_amop entry (just to give a nicer error message)
1329  */
1330  if (isAdd &&
1332  ObjectIdGetDatum(opfamilyoid),
1335  Int16GetDatum(op->number)))
1336  ereport(ERROR,
1338  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1339  op->number,
1340  format_type_be(op->lefttype),
1342  NameListToString(opfamilyname))));
1343 
1344  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1345 
1346  /* Create the pg_amop entry */
1347  memset(values, 0, sizeof(values));
1348  memset(nulls, false, sizeof(nulls));
1349 
1351  Anum_pg_amop_oid);
1352  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1353  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1354  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1355  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1356  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1357  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1358  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1359  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1360  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1361 
1362  tup = heap_form_tuple(rel->rd_att, values, nulls);
1363 
1364  CatalogTupleInsert(rel, tup);
1365 
1366  heap_freetuple(tup);
1367 
1368  /* Make its dependencies */
1369  myself.classId = AccessMethodOperatorRelationId;
1370  myself.objectId = entryoid;
1371  myself.objectSubId = 0;
1372 
1373  referenced.classId = OperatorRelationId;
1374  referenced.objectId = op->object;
1375  referenced.objectSubId = 0;
1376 
1377  if (OidIsValid(opclassoid))
1378  {
1379  /* if contained in an opclass, use a NORMAL dep on operator */
1380  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1381 
1382  /* ... and an INTERNAL dep on the opclass */
1383  referenced.classId = OperatorClassRelationId;
1384  referenced.objectId = opclassoid;
1385  referenced.objectSubId = 0;
1386  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1387  }
1388  else
1389  {
1390  /* if "loose" in the opfamily, use a AUTO dep on operator */
1391  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1392 
1393  /* ... and an AUTO dep on the opfamily */
1394  referenced.classId = OperatorFamilyRelationId;
1395  referenced.objectId = opfamilyoid;
1396  referenced.objectSubId = 0;
1397  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1398  }
1399 
1400  /* A search operator also needs a dep on the referenced opfamily */
1401  if (OidIsValid(op->sortfamily))
1402  {
1403  referenced.classId = OperatorFamilyRelationId;
1404  referenced.objectId = op->sortfamily;
1405  referenced.objectSubId = 0;
1406  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1407  }
1408  /* Post create hook of this access method operator */
1409  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1410  entryoid, 0);
1411  }
1412 
1414 }
1415 
1416 /*
1417  * Dump the procedures (support routines) to pg_amproc
1418  *
1419  * We also make dependency entries in pg_depend for the opfamily entries.
1420  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1421  * else make an AUTO dependency on the opfamily.
1422  */
1423 static void
1424 storeProcedures(List *opfamilyname, Oid amoid,
1425  Oid opfamilyoid, Oid opclassoid,
1426  List *procedures, bool isAdd)
1427 {
1428  Relation rel;
1429  Datum values[Natts_pg_amproc];
1430  bool nulls[Natts_pg_amproc];
1431  HeapTuple tup;
1432  Oid entryoid;
1433  ObjectAddress myself,
1434  referenced;
1435  ListCell *l;
1436 
1437  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1438 
1439  foreach(l, procedures)
1440  {
1441  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1442 
1443  /*
1444  * If adding to an existing family, check for conflict with an
1445  * existing pg_amproc entry (just to give a nicer error message)
1446  */
1447  if (isAdd &&
1449  ObjectIdGetDatum(opfamilyoid),
1450  ObjectIdGetDatum(proc->lefttype),
1451  ObjectIdGetDatum(proc->righttype),
1452  Int16GetDatum(proc->number)))
1453  ereport(ERROR,
1455  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1456  proc->number,
1457  format_type_be(proc->lefttype),
1458  format_type_be(proc->righttype),
1459  NameListToString(opfamilyname))));
1460 
1461  /* Create the pg_amproc entry */
1462  memset(values, 0, sizeof(values));
1463  memset(nulls, false, sizeof(nulls));
1464 
1466  Anum_pg_amproc_oid);
1467  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1468  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1469  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1470  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1471  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1472  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1473 
1474  tup = heap_form_tuple(rel->rd_att, values, nulls);
1475 
1476  CatalogTupleInsert(rel, tup);
1477 
1478  heap_freetuple(tup);
1479 
1480  /* Make its dependencies */
1481  myself.classId = AccessMethodProcedureRelationId;
1482  myself.objectId = entryoid;
1483  myself.objectSubId = 0;
1484 
1485  referenced.classId = ProcedureRelationId;
1486  referenced.objectId = proc->object;
1487  referenced.objectSubId = 0;
1488 
1489  if (OidIsValid(opclassoid))
1490  {
1491  /* if contained in an opclass, use a NORMAL dep on procedure */
1492  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1493 
1494  /* ... and an INTERNAL dep on the opclass */
1495  referenced.classId = OperatorClassRelationId;
1496  referenced.objectId = opclassoid;
1497  referenced.objectSubId = 0;
1498  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1499  }
1500  else
1501  {
1502  /* if "loose" in the opfamily, use a AUTO dep on procedure */
1503  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1504 
1505  /* ... and an AUTO dep on the opfamily */
1506  referenced.classId = OperatorFamilyRelationId;
1507  referenced.objectId = opfamilyoid;
1508  referenced.objectSubId = 0;
1509  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1510  }
1511  /* Post create hook of access method procedure */
1512  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1513  entryoid, 0);
1514  }
1515 
1517 }
1518 
1519 
1520 /*
1521  * Remove operator entries from an opfamily.
1522  *
1523  * Note: this is only allowed for "loose" members of an opfamily, hence
1524  * behavior is always RESTRICT.
1525  */
1526 static void
1527 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1528  List *operators)
1529 {
1530  ListCell *l;
1531 
1532  foreach(l, operators)
1533  {
1534  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1535  Oid amopid;
1536  ObjectAddress object;
1537 
1538  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1539  ObjectIdGetDatum(opfamilyoid),
1542  Int16GetDatum(op->number));
1543  if (!OidIsValid(amopid))
1544  ereport(ERROR,
1545  (errcode(ERRCODE_UNDEFINED_OBJECT),
1546  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1547  op->number,
1548  format_type_be(op->lefttype),
1550  NameListToString(opfamilyname))));
1551 
1552  object.classId = AccessMethodOperatorRelationId;
1553  object.objectId = amopid;
1554  object.objectSubId = 0;
1555 
1556  performDeletion(&object, DROP_RESTRICT, 0);
1557  }
1558 }
1559 
1560 /*
1561  * Remove procedure entries from an opfamily.
1562  *
1563  * Note: this is only allowed for "loose" members of an opfamily, hence
1564  * behavior is always RESTRICT.
1565  */
1566 static void
1567 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1568  List *procedures)
1569 {
1570  ListCell *l;
1571 
1572  foreach(l, procedures)
1573  {
1574  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1575  Oid amprocid;
1576  ObjectAddress object;
1577 
1578  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1579  ObjectIdGetDatum(opfamilyoid),
1582  Int16GetDatum(op->number));
1583  if (!OidIsValid(amprocid))
1584  ereport(ERROR,
1585  (errcode(ERRCODE_UNDEFINED_OBJECT),
1586  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1587  op->number,
1588  format_type_be(op->lefttype),
1590  NameListToString(opfamilyname))));
1591 
1592  object.classId = AccessMethodProcedureRelationId;
1593  object.objectId = amprocid;
1594  object.objectSubId = 0;
1595 
1596  performDeletion(&object, DROP_RESTRICT, 0);
1597  }
1598 }
1599 
1600 /*
1601  * Deletion subroutines for use by dependency.c.
1602  */
1603 void
1605 {
1606  Relation rel;
1607  HeapTuple tup;
1608 
1609  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
1610 
1611  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1612  if (!HeapTupleIsValid(tup)) /* should not happen */
1613  elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1614 
1615  CatalogTupleDelete(rel, &tup->t_self);
1616 
1617  ReleaseSysCache(tup);
1618 
1620 }
1621 
1622 void
1624 {
1625  Relation rel;
1626  HeapTuple tup;
1627 
1628  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
1629 
1630  tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1631  if (!HeapTupleIsValid(tup)) /* should not happen */
1632  elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1633 
1634  CatalogTupleDelete(rel, &tup->t_self);
1635 
1636  ReleaseSysCache(tup);
1637 
1639 }
1640 
1641 void
1643 {
1644  Relation rel;
1645  HeapTuple tup;
1646  ScanKeyData skey[1];
1647  SysScanDesc scan;
1648 
1649  ScanKeyInit(&skey[0],
1650  Anum_pg_amop_oid,
1651  BTEqualStrategyNumber, F_OIDEQ,
1652  ObjectIdGetDatum(entryOid));
1653 
1654  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1655 
1657  NULL, 1, skey);
1658 
1659  /* we expect exactly one match */
1660  tup = systable_getnext(scan);
1661  if (!HeapTupleIsValid(tup))
1662  elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1663 
1664  CatalogTupleDelete(rel, &tup->t_self);
1665 
1666  systable_endscan(scan);
1668 }
1669 
1670 void
1672 {
1673  Relation rel;
1674  HeapTuple tup;
1675  ScanKeyData skey[1];
1676  SysScanDesc scan;
1677 
1678  ScanKeyInit(&skey[0],
1679  Anum_pg_amproc_oid,
1680  BTEqualStrategyNumber, F_OIDEQ,
1681  ObjectIdGetDatum(entryOid));
1682 
1683  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1684 
1686  NULL, 1, skey);
1687 
1688  /* we expect exactly one match */
1689  tup = systable_getnext(scan);
1690  if (!HeapTupleIsValid(tup))
1691  elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1692 
1693  CatalogTupleDelete(rel, &tup->t_self);
1694 
1695  systable_endscan(scan);
1697 }
1698 
1699 /*
1700  * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
1701  *
1702  * Is there an operator class with the given name and signature already
1703  * in the given namespace? If so, raise an appropriate error message.
1704  */
1705 void
1706 IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
1707  Oid opcnamespace)
1708 {
1709  /* make sure the new name doesn't exist */
1711  ObjectIdGetDatum(opcmethod),
1712  CStringGetDatum(opcname),
1713  ObjectIdGetDatum(opcnamespace)))
1714  ereport(ERROR,
1716  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1717  opcname,
1718  get_am_name(opcmethod),
1719  get_namespace_name(opcnamespace))));
1720 }
1721 
1722 /*
1723  * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
1724  *
1725  * Is there an operator family with the given name and signature already
1726  * in the given namespace? If so, raise an appropriate error message.
1727  */
1728 void
1729 IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
1730  Oid opfnamespace)
1731 {
1732  /* make sure the new name doesn't exist */
1734  ObjectIdGetDatum(opfmethod),
1735  CStringGetDatum(opfname),
1736  ObjectIdGetDatum(opfnamespace)))
1737  ereport(ERROR,
1739  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1740  opfname,
1741  get_am_name(opfmethod),
1742  get_namespace_name(opfnamespace))));
1743 }
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:140
#define NIL
Definition: pg_list.h:65
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:323
#define NameGetDatum(X)
Definition: postgres.h:595
uint16 amsupport
Definition: amapi.h:173
#define BTORDER_PROC
Definition: nbtree.h:392
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2885
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1067
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
Definition: syscache.h:36
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:393
void RemoveOpClassById(Oid opclassOid)
Definition: opclasscmds.c:1623
Oid GetUserId(void)
Definition: miscinit.c:380
TypeName * storedtype
Definition: parsenodes.h:2596
bool amcanorderbyop
Definition: amapi.h:177
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2987
#define PointerGetDatum(X)
Definition: postgres.h:556
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:477
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:165
bool amstorage
Definition: amapi.h:191
#define Int16GetDatum(X)
Definition: postgres.h:451
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:189
#define AccessMethodOperatorOidIndexId
Definition: indexing.h:81
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4807
int errcode(int sqlerrcode)
Definition: elog.c:570
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:84
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1567
#define HASHEXTENDED_PROC
Definition: hash.h:338
bool superuser(void)
Definition: superuser.c:47
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
void DeconstructQualifiedName(List *names, char **nspname_p, char **objname_p)
Definition: namespace.c:2801
Oid LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright, bool noError, int location)
Definition: parse_oper.c:102
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:223
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
void RemoveAmProcEntryById(Oid entryOid)
Definition: opclasscmds.c:1671
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
bool pg_type_ownercheck(Oid type_oid, Oid roleid)
Definition: aclchk.c:4781
ObjectAddress DefineOpClass(CreateOpClassStmt *stmt)
Definition: opclasscmds.c:331
int namestrcpy(Name name, const char *str)
Definition: name.c:250
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1792
#define OidIsValid(objectId)
Definition: c.h:638
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4693
void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, Oid opcnamespace)
Definition: opclasscmds.c:1706
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
#define OpclassAmNameNspIndexId
Definition: indexing.h:195
#define lsecond(l)
Definition: pg_list.h:200
void aclcheck_error_type(AclResult aclerr, Oid typeOid)
Definition: aclchk.c:3666
#define AccessMethodProcedureOidIndexId
Definition: indexing.h:86
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2582
char * get_opname(Oid opno)
Definition: lsyscache.c:1117
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1527
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3353
Oid OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1875
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:962
#define linitial(l)
Definition: pg_list.h:195
#define BTINRANGE_PROC
Definition: nbtree.h:394
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
#define SearchSysCacheExists3(cacheId, key1, key2, key3)
Definition: syscache.h:187
IndexAmRoutine * GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
Definition: amapi.c:56
char * get_func_name(Oid funcid)
Definition: lsyscache.c:1410
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1146
ItemPointerData t_self
Definition: htup.h:65
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Definition: c.h:603
TypeName * datatype
Definition: parsenodes.h:2577
void RemoveOpFamilyById(Oid opfamilyOid)
Definition: opclasscmds.c:1604
ObjectWithArgs * name
Definition: parsenodes.h:2590
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:187
char * get_am_name(Oid amOid)
Definition: amcmds.c:216
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:860
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1267
#define CStringGetDatum(X)
Definition: postgres.h:578
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:315
#define HASHSTANDARD_PROC
Definition: hash.h:337
#define ereport(elevel, rest)
Definition: elog.h:141
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:246
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
List * lappend(List *list, void *datum)
Definition: list.c:321
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
char * NameListToString(List *names)
Definition: namespace.c:3094
void RemoveAmOpEntryById(Oid entryOid)
Definition: opclasscmds.c:1642
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1038
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void * palloc0(Size size)
Definition: mcxt.c:955
AclResult
Definition: acl.h:177
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
#define GetSysCacheOid4(cacheId, oidcol, key1, key2, key3, key4)
Definition: syscache.h:198
TupleDesc rd_att
Definition: rel.h:84
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
#define OpclassOidIndexId
Definition: indexing.h:197
#define BoolGetDatum(X)
Definition: postgres.h:402
#define InvalidOid
Definition: postgres_ext.h:36
RegProcedure get_opcode(Oid opno)
Definition: lsyscache.c:1092
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2583
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:138
static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:837
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2584
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:142
static int list_length(const List *l)
Definition: pg_list.h:169
static void storeProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *procedures, bool isAdd)
Definition: opclasscmds.c:1424
FormData_pg_operator * Form_pg_operator
Definition: pg_operator.h:84
#define CharGetDatum(X)
Definition: postgres.h:416
Oid AlterOpFamily(AlterOpFamilyStmt *stmt)
Definition: opclasscmds.c:776
ObjectAddress DefineOpFamily(CreateOpFamilyStmt *stmt)
Definition: opclasscmds.c:731
uint16 amstrategies
Definition: amapi.h:171
static Datum values[MAXATTR]
Definition: bootstrap.c:167
FormData_pg_am * Form_pg_am
Definition: pg_am.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2160
#define NameStr(name)
Definition: c.h:609
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1133
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1306
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:83
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:33
Definition: pg_list.h:50
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define BTEqualStrategyNumber
Definition: stratnum.h:31
bool pg_proc_ownercheck(Oid proc_oid, Oid roleid)
Definition: aclchk.c:4833
void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, Oid opfnamespace)
Definition: opclasscmds.c:1729
#define OpfamilyOidIndexId
Definition: indexing.h:207
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:292