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