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/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 static void AlterOpFamilyAdd(AlterOpFamilyStmt *stmt,
54  Oid amoid, Oid opfamilyoid,
55  int maxOpNumber, int maxProcNumber,
56  List *items);
57 static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt,
58  Oid amoid, Oid opfamilyoid,
59  int maxOpNumber, int maxProcNumber,
60  List *items);
61 static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
62 static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
63 static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
64 static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
65 static void storeOperators(List *opfamilyname, Oid amoid,
66  Oid opfamilyoid, Oid opclassoid,
67  List *operators, bool isAdd);
68 static void storeProcedures(List *opfamilyname, Oid amoid,
69  Oid opfamilyoid, Oid opclassoid,
70  List *procedures, bool isAdd);
71 static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
72  List *operators);
73 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
74  List *procedures);
75 
76 /*
77  * OpFamilyCacheLookup
78  * Look up an existing opfamily by name.
79  *
80  * Returns a syscache tuple reference, or NULL if not found.
81  */
82 static HeapTuple
83 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
84 {
85  char *schemaname;
86  char *opfname;
87  HeapTuple htup;
88 
89  /* deconstruct the name list */
90  DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
91 
92  if (schemaname)
93  {
94  /* Look in specific schema only */
95  Oid namespaceId;
96 
97  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
98  if (!OidIsValid(namespaceId))
99  htup = NULL;
100  else
102  ObjectIdGetDatum(amID),
103  PointerGetDatum(opfname),
104  ObjectIdGetDatum(namespaceId));
105  }
106  else
107  {
108  /* Unqualified opfamily name, so search the search path */
109  Oid opfID = OpfamilynameGetOpfid(amID, opfname);
110 
111  if (!OidIsValid(opfID))
112  htup = NULL;
113  else
115  }
116 
117  if (!HeapTupleIsValid(htup) && !missing_ok)
118  {
119  HeapTuple amtup;
120 
121  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
122  if (!HeapTupleIsValid(amtup))
123  elog(ERROR, "cache lookup failed for access method %u", amID);
124  ereport(ERROR,
125  (errcode(ERRCODE_UNDEFINED_OBJECT),
126  errmsg("operator family \"%s\" does not exist for access method \"%s\"",
127  NameListToString(opfamilyname),
128  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
129  }
130 
131  return htup;
132 }
133 
134 /*
135  * get_opfamily_oid
136  * find an opfamily OID by possibly qualified name
137  *
138  * If not found, returns InvalidOid if missing_ok, else throws error.
139  */
140 Oid
141 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
142 {
143  HeapTuple htup;
144  Form_pg_opfamily opfamform;
145  Oid opfID;
146 
147  htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
148  if (!HeapTupleIsValid(htup))
149  return InvalidOid;
150  opfamform = (Form_pg_opfamily) GETSTRUCT(htup);
151  opfID = opfamform->oid;
152  ReleaseSysCache(htup);
153 
154  return opfID;
155 }
156 
157 /*
158  * OpClassCacheLookup
159  * Look up an existing opclass by name.
160  *
161  * Returns a syscache tuple reference, or NULL if not found.
162  */
163 static HeapTuple
164 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
165 {
166  char *schemaname;
167  char *opcname;
168  HeapTuple htup;
169 
170  /* deconstruct the name list */
171  DeconstructQualifiedName(opclassname, &schemaname, &opcname);
172 
173  if (schemaname)
174  {
175  /* Look in specific schema only */
176  Oid namespaceId;
177 
178  namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
179  if (!OidIsValid(namespaceId))
180  htup = NULL;
181  else
183  ObjectIdGetDatum(amID),
184  PointerGetDatum(opcname),
185  ObjectIdGetDatum(namespaceId));
186  }
187  else
188  {
189  /* Unqualified opclass name, so search the search path */
190  Oid opcID = OpclassnameGetOpcid(amID, opcname);
191 
192  if (!OidIsValid(opcID))
193  htup = NULL;
194  else
195  htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
196  }
197 
198  if (!HeapTupleIsValid(htup) && !missing_ok)
199  {
200  HeapTuple amtup;
201 
202  amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
203  if (!HeapTupleIsValid(amtup))
204  elog(ERROR, "cache lookup failed for access method %u", amID);
205  ereport(ERROR,
206  (errcode(ERRCODE_UNDEFINED_OBJECT),
207  errmsg("operator class \"%s\" does not exist for access method \"%s\"",
208  NameListToString(opclassname),
209  NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
210  }
211 
212  return htup;
213 }
214 
215 /*
216  * get_opclass_oid
217  * find an opclass OID by possibly qualified name
218  *
219  * If not found, returns InvalidOid if missing_ok, else throws error.
220  */
221 Oid
222 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
223 {
224  HeapTuple htup;
225  Form_pg_opclass opcform;
226  Oid opcID;
227 
228  htup = OpClassCacheLookup(amID, opclassname, missing_ok);
229  if (!HeapTupleIsValid(htup))
230  return InvalidOid;
231  opcform = (Form_pg_opclass) GETSTRUCT(htup);
232  opcID = opcform->oid;
233  ReleaseSysCache(htup);
234 
235  return opcID;
236 }
237 
238 /*
239  * CreateOpFamily
240  * Internal routine to make the catalog entry for a new operator family.
241  *
242  * Caller must have done permissions checks etc. already.
243  */
244 static ObjectAddress
245 CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
246 {
247  Oid opfamilyoid;
248  Relation rel;
249  HeapTuple tup;
250  Datum values[Natts_pg_opfamily];
251  bool nulls[Natts_pg_opfamily];
252  NameData opfName;
253  ObjectAddress myself,
254  referenced;
255 
256  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
257 
258  /*
259  * Make sure there is no existing opfamily of this name (this is just to
260  * give a more friendly error message than "duplicate key").
261  */
263  ObjectIdGetDatum(amoid),
264  CStringGetDatum(opfname),
265  ObjectIdGetDatum(namespaceoid)))
266  ereport(ERROR,
268  errmsg("operator family \"%s\" for access method \"%s\" already exists",
269  opfname, amname)));
270 
271  /*
272  * Okay, let's create the pg_opfamily entry.
273  */
274  memset(values, 0, sizeof(values));
275  memset(nulls, false, sizeof(nulls));
276 
277  opfamilyoid = GetNewOidWithIndex(rel, OpfamilyOidIndexId,
278  Anum_pg_opfamily_oid);
279  values[Anum_pg_opfamily_oid - 1] = ObjectIdGetDatum(opfamilyoid);
280  values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
281  namestrcpy(&opfName, opfname);
282  values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
283  values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
284  values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
285 
286  tup = heap_form_tuple(rel->rd_att, values, nulls);
287 
288  CatalogTupleInsert(rel, tup);
289 
290  heap_freetuple(tup);
291 
292  /*
293  * Create dependencies for the opfamily proper.
294  */
295  myself.classId = OperatorFamilyRelationId;
296  myself.objectId = opfamilyoid;
297  myself.objectSubId = 0;
298 
299  /* dependency on access method */
300  referenced.classId = AccessMethodRelationId;
301  referenced.objectId = amoid;
302  referenced.objectSubId = 0;
303  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
304 
305  /* dependency on namespace */
306  referenced.classId = NamespaceRelationId;
307  referenced.objectId = namespaceoid;
308  referenced.objectSubId = 0;
309  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
310 
311  /* dependency on owner */
312  recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
313 
314  /* dependency on extension */
315  recordDependencyOnCurrentExtension(&myself, false);
316 
317  /* Post creation hook for new operator family */
318  InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
319 
321 
322  return myself;
323 }
324 
325 /*
326  * DefineOpClass
327  * Define a new index operator class.
328  */
331 {
332  char *opcname; /* name of opclass we're creating */
333  Oid amoid, /* our AM's oid */
334  typeoid, /* indexable datatype oid */
335  storageoid, /* storage datatype oid, if any */
336  namespaceoid, /* namespace to create opclass in */
337  opfamilyoid, /* oid of containing opfamily */
338  opclassoid; /* oid of opclass we create */
339  int maxOpNumber, /* amstrategies value */
340  maxProcNumber; /* amsupport value */
341  bool amstorage; /* amstorage flag */
342  List *operators; /* OpFamilyMember list for operators */
343  List *procedures; /* OpFamilyMember list for support procs */
344  ListCell *l;
345  Relation rel;
346  HeapTuple tup;
347  Form_pg_am amform;
348  IndexAmRoutine *amroutine;
349  Datum values[Natts_pg_opclass];
350  bool nulls[Natts_pg_opclass];
351  AclResult aclresult;
352  NameData opcName;
353  ObjectAddress myself,
354  referenced;
355 
356  /* Convert list of names to a name and namespace */
357  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
358  &opcname);
359 
360  /* Check we have creation rights in target namespace */
361  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
362  if (aclresult != ACLCHECK_OK)
363  aclcheck_error(aclresult, OBJECT_SCHEMA,
364  get_namespace_name(namespaceoid));
365 
366  /* Get necessary info about access method */
368  if (!HeapTupleIsValid(tup))
369  ereport(ERROR,
370  (errcode(ERRCODE_UNDEFINED_OBJECT),
371  errmsg("access method \"%s\" does not exist",
372  stmt->amname)));
373 
374  amform = (Form_pg_am) GETSTRUCT(tup);
375  amoid = amform->oid;
376  amroutine = GetIndexAmRoutineByAmId(amoid, false);
377  ReleaseSysCache(tup);
378 
379  maxOpNumber = amroutine->amstrategies;
380  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
381  if (maxOpNumber <= 0)
382  maxOpNumber = SHRT_MAX;
383  maxProcNumber = amroutine->amsupport;
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->object = operOid;
519  member->number = item->number;
520  member->sortfamily = sortfamilyOid;
521  assignOperTypes(member, amoid, typeoid);
522  addFamilyMember(&operators, member, false);
523  break;
525  if (item->number <= 0 || item->number > maxProcNumber)
526  ereport(ERROR,
527  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
528  errmsg("invalid function number %d,"
529  " must be between 1 and %d",
530  item->number, maxProcNumber)));
531  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
532 #ifdef NOT_USED
533  /* XXX this is unnecessary given the superuser check above */
534  /* Caller must own function */
535  if (!pg_proc_ownercheck(funcOid, GetUserId()))
537  get_func_name(funcOid));
538 #endif
539 
540  /* Save the info */
541  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
542  member->object = funcOid;
543  member->number = item->number;
544 
545  /* allow overriding of the function's actual arg types */
546  if (item->class_args)
548  &member->lefttype, &member->righttype);
549 
550  assignProcTypes(member, amoid, typeoid);
551  addFamilyMember(&procedures, member, true);
552  break;
554  if (OidIsValid(storageoid))
555  ereport(ERROR,
556  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
557  errmsg("storage type specified more than once")));
558  storageoid = typenameTypeId(NULL, item->storedtype);
559 
560 #ifdef NOT_USED
561  /* XXX this is unnecessary given the superuser check above */
562  /* Check we have ownership of the datatype */
563  if (!pg_type_ownercheck(storageoid, GetUserId()))
565 #endif
566  break;
567  default:
568  elog(ERROR, "unrecognized item type: %d", item->itemtype);
569  break;
570  }
571  }
572 
573  /*
574  * If storagetype is specified, make sure it's legal.
575  */
576  if (OidIsValid(storageoid))
577  {
578  /* Just drop the spec if same as column datatype */
579  if (storageoid == typeoid)
580  storageoid = InvalidOid;
581  else if (!amstorage)
582  ereport(ERROR,
583  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
584  errmsg("storage type cannot be different from data type for access method \"%s\"",
585  stmt->amname)));
586  }
587 
588  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
589 
590  /*
591  * Make sure there is no existing opclass of this name (this is just to
592  * give a more friendly error message than "duplicate key").
593  */
595  ObjectIdGetDatum(amoid),
596  CStringGetDatum(opcname),
597  ObjectIdGetDatum(namespaceoid)))
598  ereport(ERROR,
600  errmsg("operator class \"%s\" for access method \"%s\" already exists",
601  opcname, stmt->amname)));
602 
603  /*
604  * If we are creating a default opclass, check there isn't one already.
605  * (Note we do not restrict this test to visible opclasses; this ensures
606  * that typcache.c can find unique solutions to its questions.)
607  */
608  if (stmt->isDefault)
609  {
610  ScanKeyData skey[1];
611  SysScanDesc scan;
612 
613  ScanKeyInit(&skey[0],
614  Anum_pg_opclass_opcmethod,
615  BTEqualStrategyNumber, F_OIDEQ,
616  ObjectIdGetDatum(amoid));
617 
619  NULL, 1, skey);
620 
621  while (HeapTupleIsValid(tup = systable_getnext(scan)))
622  {
623  Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
624 
625  if (opclass->opcintype == typeoid && opclass->opcdefault)
626  ereport(ERROR,
628  errmsg("could not make operator class \"%s\" be default for type %s",
629  opcname,
630  TypeNameToString(stmt->datatype)),
631  errdetail("Operator class \"%s\" already is the default.",
632  NameStr(opclass->opcname))));
633  }
634 
635  systable_endscan(scan);
636  }
637 
638  /*
639  * Okay, let's create the pg_opclass entry.
640  */
641  memset(values, 0, sizeof(values));
642  memset(nulls, false, sizeof(nulls));
643 
644  opclassoid = GetNewOidWithIndex(rel, OpclassOidIndexId,
645  Anum_pg_opclass_oid);
646  values[Anum_pg_opclass_oid - 1] = ObjectIdGetDatum(opclassoid);
647  values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
648  namestrcpy(&opcName, opcname);
649  values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
650  values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
651  values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
652  values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
653  values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
654  values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
655  values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
656 
657  tup = heap_form_tuple(rel->rd_att, values, nulls);
658 
659  CatalogTupleInsert(rel, tup);
660 
661  heap_freetuple(tup);
662 
663  /*
664  * Now add tuples to pg_amop and pg_amproc tying in the operators and
665  * functions. Dependencies on them are inserted, too.
666  */
667  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
668  opclassoid, operators, false);
669  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
670  opclassoid, procedures, false);
671 
672  /* let event triggers know what happened */
673  EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
674 
675  /*
676  * Create dependencies for the opclass proper. Note: we do not need a
677  * dependency link to the AM, because that exists through the opfamily.
678  */
679  myself.classId = OperatorClassRelationId;
680  myself.objectId = opclassoid;
681  myself.objectSubId = 0;
682 
683  /* dependency on namespace */
684  referenced.classId = NamespaceRelationId;
685  referenced.objectId = namespaceoid;
686  referenced.objectSubId = 0;
687  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
688 
689  /* dependency on opfamily */
690  referenced.classId = OperatorFamilyRelationId;
691  referenced.objectId = opfamilyoid;
692  referenced.objectSubId = 0;
693  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
694 
695  /* dependency on indexed datatype */
696  referenced.classId = TypeRelationId;
697  referenced.objectId = typeoid;
698  referenced.objectSubId = 0;
699  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
700 
701  /* dependency on storage datatype */
702  if (OidIsValid(storageoid))
703  {
704  referenced.classId = TypeRelationId;
705  referenced.objectId = storageoid;
706  referenced.objectSubId = 0;
707  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
708  }
709 
710  /* dependency on owner */
711  recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
712 
713  /* dependency on extension */
714  recordDependencyOnCurrentExtension(&myself, false);
715 
716  /* Post creation hook for new operator class */
717  InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
718 
720 
721  return myself;
722 }
723 
724 
725 /*
726  * DefineOpFamily
727  * Define a new index operator family.
728  */
731 {
732  char *opfname; /* name of opfamily we're creating */
733  Oid amoid, /* our AM's oid */
734  namespaceoid; /* namespace to create opfamily in */
735  AclResult aclresult;
736 
737  /* Convert list of names to a name and namespace */
738  namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
739  &opfname);
740 
741  /* Check we have creation rights in target namespace */
742  aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
743  if (aclresult != ACLCHECK_OK)
744  aclcheck_error(aclresult, OBJECT_SCHEMA,
745  get_namespace_name(namespaceoid));
746 
747  /* Get access method OID, throwing an error if it doesn't exist. */
748  amoid = get_index_am_oid(stmt->amname, false);
749 
750  /* XXX Should we make any privilege check against the AM? */
751 
752  /*
753  * Currently, we require superuser privileges to create an opfamily. See
754  * comments in DefineOpClass.
755  */
756  if (!superuser())
757  ereport(ERROR,
758  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
759  errmsg("must be superuser to create an operator family")));
760 
761  /* Insert pg_opfamily catalog entry */
762  return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
763 }
764 
765 
766 /*
767  * AlterOpFamily
768  * Add or remove operators/procedures within an existing operator family.
769  *
770  * Note: this implements only ALTER OPERATOR FAMILY ... ADD/DROP. Some
771  * other commands called ALTER OPERATOR FAMILY exist, but go through
772  * different code paths.
773  */
774 Oid
776 {
777  Oid amoid, /* our AM's oid */
778  opfamilyoid; /* oid of opfamily */
779  int maxOpNumber, /* amstrategies value */
780  maxProcNumber; /* amsupport value */
781  HeapTuple tup;
782  Form_pg_am amform;
783  IndexAmRoutine *amroutine;
784 
785  /* Get necessary info about access method */
787  if (!HeapTupleIsValid(tup))
788  ereport(ERROR,
789  (errcode(ERRCODE_UNDEFINED_OBJECT),
790  errmsg("access method \"%s\" does not exist",
791  stmt->amname)));
792 
793  amform = (Form_pg_am) GETSTRUCT(tup);
794  amoid = amform->oid;
795  amroutine = GetIndexAmRoutineByAmId(amoid, false);
796  ReleaseSysCache(tup);
797 
798  maxOpNumber = amroutine->amstrategies;
799  /* if amstrategies is zero, just enforce that op numbers fit in int16 */
800  if (maxOpNumber <= 0)
801  maxOpNumber = SHRT_MAX;
802  maxProcNumber = amroutine->amsupport;
803 
804  /* XXX Should we make any privilege check against the AM? */
805 
806  /* Look up the opfamily */
807  opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
808 
809  /*
810  * Currently, we require superuser privileges to alter an opfamily.
811  *
812  * XXX re-enable NOT_USED code sections below if you remove this test.
813  */
814  if (!superuser())
815  ereport(ERROR,
816  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
817  errmsg("must be superuser to alter an operator family")));
818 
819  /*
820  * ADD and DROP cases need separate code from here on down.
821  */
822  if (stmt->isDrop)
823  AlterOpFamilyDrop(stmt, amoid, opfamilyoid,
824  maxOpNumber, maxProcNumber, stmt->items);
825  else
826  AlterOpFamilyAdd(stmt, amoid, opfamilyoid,
827  maxOpNumber, maxProcNumber, stmt->items);
828 
829  return opfamilyoid;
830 }
831 
832 /*
833  * ADD part of ALTER OP FAMILY
834  */
835 static void
836 AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
837  int maxOpNumber, int maxProcNumber, List *items)
838 {
839  List *operators; /* OpFamilyMember list for operators */
840  List *procedures; /* OpFamilyMember list for support procs */
841  ListCell *l;
842 
843  operators = NIL;
844  procedures = NIL;
845 
846  /*
847  * Scan the "items" list to obtain additional info.
848  */
849  foreach(l, items)
850  {
852  Oid operOid;
853  Oid funcOid;
854  Oid sortfamilyOid;
856 
857  switch (item->itemtype)
858  {
860  if (item->number <= 0 || item->number > maxOpNumber)
861  ereport(ERROR,
862  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
863  errmsg("invalid operator number %d,"
864  " must be between 1 and %d",
865  item->number, maxOpNumber)));
866  if (item->name->objargs != NIL)
867  operOid = LookupOperWithArgs(item->name, false);
868  else
869  {
870  ereport(ERROR,
871  (errcode(ERRCODE_SYNTAX_ERROR),
872  errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
873  operOid = InvalidOid; /* keep compiler quiet */
874  }
875 
876  if (item->order_family)
877  sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
878  item->order_family,
879  false);
880  else
881  sortfamilyOid = InvalidOid;
882 
883 #ifdef NOT_USED
884  /* XXX this is unnecessary given the superuser check above */
885  /* Caller must own operator and its underlying function */
886  if (!pg_oper_ownercheck(operOid, GetUserId()))
888  get_opname(operOid));
889  funcOid = get_opcode(operOid);
890  if (!pg_proc_ownercheck(funcOid, GetUserId()))
892  get_func_name(funcOid));
893 #endif
894 
895  /* Save the info */
896  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
897  member->object = operOid;
898  member->number = item->number;
899  member->sortfamily = sortfamilyOid;
900  assignOperTypes(member, amoid, InvalidOid);
901  addFamilyMember(&operators, member, false);
902  break;
904  if (item->number <= 0 || item->number > maxProcNumber)
905  ereport(ERROR,
906  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
907  errmsg("invalid function number %d,"
908  " must be between 1 and %d",
909  item->number, maxProcNumber)));
910  funcOid = LookupFuncWithArgs(OBJECT_FUNCTION, item->name, false);
911 #ifdef NOT_USED
912  /* XXX this is unnecessary given the superuser check above */
913  /* Caller must own function */
914  if (!pg_proc_ownercheck(funcOid, GetUserId()))
916  get_func_name(funcOid));
917 #endif
918 
919  /* Save the info */
920  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
921  member->object = funcOid;
922  member->number = item->number;
923 
924  /* allow overriding of the function's actual arg types */
925  if (item->class_args)
927  &member->lefttype, &member->righttype);
928 
929  assignProcTypes(member, amoid, InvalidOid);
930  addFamilyMember(&procedures, member, true);
931  break;
933  ereport(ERROR,
934  (errcode(ERRCODE_SYNTAX_ERROR),
935  errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
936  break;
937  default:
938  elog(ERROR, "unrecognized item type: %d", item->itemtype);
939  break;
940  }
941  }
942 
943  /*
944  * Add tuples to pg_amop and pg_amproc tying in the operators and
945  * functions. Dependencies on them are inserted, too.
946  */
947  storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
948  InvalidOid, operators, true);
949  storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
950  InvalidOid, procedures, true);
951 
952  /* make information available to event triggers */
953  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
954  operators, procedures);
955 }
956 
957 /*
958  * DROP part of ALTER OP FAMILY
959  */
960 static void
961 AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
962  int maxOpNumber, int maxProcNumber, List *items)
963 {
964  List *operators; /* OpFamilyMember list for operators */
965  List *procedures; /* OpFamilyMember list for support procs */
966  ListCell *l;
967 
968  operators = NIL;
969  procedures = NIL;
970 
971  /*
972  * Scan the "items" list to obtain additional info.
973  */
974  foreach(l, items)
975  {
977  Oid lefttype,
978  righttype;
980 
981  switch (item->itemtype)
982  {
984  if (item->number <= 0 || item->number > maxOpNumber)
985  ereport(ERROR,
986  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
987  errmsg("invalid operator number %d,"
988  " must be between 1 and %d",
989  item->number, maxOpNumber)));
990  processTypesSpec(item->class_args, &lefttype, &righttype);
991  /* Save the info */
992  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
993  member->number = item->number;
994  member->lefttype = lefttype;
995  member->righttype = righttype;
996  addFamilyMember(&operators, member, false);
997  break;
999  if (item->number <= 0 || item->number > maxProcNumber)
1000  ereport(ERROR,
1001  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1002  errmsg("invalid function number %d,"
1003  " must be between 1 and %d",
1004  item->number, maxProcNumber)));
1005  processTypesSpec(item->class_args, &lefttype, &righttype);
1006  /* Save the info */
1007  member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
1008  member->number = item->number;
1009  member->lefttype = lefttype;
1010  member->righttype = righttype;
1011  addFamilyMember(&procedures, member, true);
1012  break;
1014  /* grammar prevents this from appearing */
1015  default:
1016  elog(ERROR, "unrecognized item type: %d", item->itemtype);
1017  break;
1018  }
1019  }
1020 
1021  /*
1022  * Remove tuples from pg_amop and pg_amproc.
1023  */
1024  dropOperators(stmt->opfamilyname, amoid, opfamilyoid, operators);
1025  dropProcedures(stmt->opfamilyname, amoid, opfamilyoid, procedures);
1026 
1027  /* make information available to event triggers */
1028  EventTriggerCollectAlterOpFam(stmt, opfamilyoid,
1029  operators, procedures);
1030 }
1031 
1032 
1033 /*
1034  * Deal with explicit arg types used in ALTER ADD/DROP
1035  */
1036 static void
1037 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
1038 {
1039  TypeName *typeName;
1040 
1041  Assert(args != NIL);
1042 
1043  typeName = (TypeName *) linitial(args);
1044  *lefttype = typenameTypeId(NULL, typeName);
1045 
1046  if (list_length(args) > 1)
1047  {
1048  typeName = (TypeName *) lsecond(args);
1049  *righttype = typenameTypeId(NULL, typeName);
1050  }
1051  else
1052  *righttype = *lefttype;
1053 
1054  if (list_length(args) > 2)
1055  ereport(ERROR,
1056  (errcode(ERRCODE_SYNTAX_ERROR),
1057  errmsg("one or two argument types must be specified")));
1058 }
1059 
1060 
1061 /*
1062  * Determine the lefttype/righttype to assign to an operator,
1063  * and do any validity checking we can manage.
1064  */
1065 static void
1067 {
1068  Operator optup;
1069  Form_pg_operator opform;
1070 
1071  /* Fetch the operator definition */
1072  optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
1073  if (!HeapTupleIsValid(optup))
1074  elog(ERROR, "cache lookup failed for operator %u", member->object);
1075  opform = (Form_pg_operator) GETSTRUCT(optup);
1076 
1077  /*
1078  * Opfamily operators must be binary.
1079  */
1080  if (opform->oprkind != 'b')
1081  ereport(ERROR,
1082  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1083  errmsg("index operators must be binary")));
1084 
1085  if (OidIsValid(member->sortfamily))
1086  {
1087  /*
1088  * Ordering op, check index supports that. (We could perhaps also
1089  * check that the operator returns a type supported by the sortfamily,
1090  * but that seems more trouble than it's worth here. If it does not,
1091  * the operator will never be matchable to any ORDER BY clause, but no
1092  * worse consequences can ensue. Also, trying to check that would
1093  * create an ordering hazard during dump/reload: it's possible that
1094  * the family has been created but not yet populated with the required
1095  * operators.)
1096  */
1097  IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
1098 
1099  if (!amroutine->amcanorderbyop)
1100  ereport(ERROR,
1101  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1102  errmsg("access method \"%s\" does not support ordering operators",
1103  get_am_name(amoid))));
1104  }
1105  else
1106  {
1107  /*
1108  * Search operators must return boolean.
1109  */
1110  if (opform->oprresult != BOOLOID)
1111  ereport(ERROR,
1112  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1113  errmsg("index search operators must return boolean")));
1114  }
1115 
1116  /*
1117  * If lefttype/righttype isn't specified, use the operator's input types
1118  */
1119  if (!OidIsValid(member->lefttype))
1120  member->lefttype = opform->oprleft;
1121  if (!OidIsValid(member->righttype))
1122  member->righttype = opform->oprright;
1123 
1124  ReleaseSysCache(optup);
1125 }
1126 
1127 /*
1128  * Determine the lefttype/righttype to assign to a support procedure,
1129  * and do any validity checking we can manage.
1130  */
1131 static void
1133 {
1134  HeapTuple proctup;
1135  Form_pg_proc procform;
1136 
1137  /* Fetch the procedure definition */
1138  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
1139  if (!HeapTupleIsValid(proctup))
1140  elog(ERROR, "cache lookup failed for function %u", member->object);
1141  procform = (Form_pg_proc) GETSTRUCT(proctup);
1142 
1143  /*
1144  * btree comparison procs must be 2-arg procs returning int4. btree
1145  * sortsupport procs must take internal and return void. btree in_range
1146  * procs must be 5-arg procs returning bool. btree equalimage procs must
1147  * take 1 arg and return bool. hash support proc 1 must be a 1-arg proc
1148  * returning int4, while proc 2 must be a 2-arg proc returning int8.
1149  * 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  else if (member->number == BTEQUALIMAGE_PROC)
1210  {
1211  if (procform->pronargs != 1)
1212  ereport(ERROR,
1213  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1214  errmsg("btree equal image functions must have one argument")));
1215  if (procform->prorettype != BOOLOID)
1216  ereport(ERROR,
1217  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1218  errmsg("btree equal image functions must return boolean")));
1219  /*
1220  * pg_amproc functions are indexed by (lefttype, righttype), but
1221  * an equalimage function can only be called at CREATE INDEX time.
1222  * The same opclass opcintype OID is always used for leftype and
1223  * righttype. Providing a cross-type routine isn't sensible.
1224  * Reject cross-type ALTER OPERATOR FAMILY ... ADD FUNCTION 4
1225  * statements here.
1226  */
1227  if (member->lefttype != member->righttype)
1228  ereport(ERROR,
1229  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1230  errmsg("btree equal image functions must not be cross-type")));
1231  }
1232  }
1233  else if (amoid == HASH_AM_OID)
1234  {
1235  if (member->number == HASHSTANDARD_PROC)
1236  {
1237  if (procform->pronargs != 1)
1238  ereport(ERROR,
1239  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1240  errmsg("hash function 1 must have one argument")));
1241  if (procform->prorettype != INT4OID)
1242  ereport(ERROR,
1243  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1244  errmsg("hash function 1 must return integer")));
1245  }
1246  else if (member->number == HASHEXTENDED_PROC)
1247  {
1248  if (procform->pronargs != 2)
1249  ereport(ERROR,
1250  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1251  errmsg("hash function 2 must have two arguments")));
1252  if (procform->prorettype != INT8OID)
1253  ereport(ERROR,
1254  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1255  errmsg("hash function 2 must return bigint")));
1256  }
1257 
1258  /*
1259  * If lefttype/righttype isn't specified, use the proc's input type
1260  */
1261  if (!OidIsValid(member->lefttype))
1262  member->lefttype = procform->proargtypes.values[0];
1263  if (!OidIsValid(member->righttype))
1264  member->righttype = procform->proargtypes.values[0];
1265  }
1266 
1267  /*
1268  * The default in CREATE OPERATOR CLASS is to use the class' opcintype as
1269  * lefttype and righttype. In CREATE or ALTER OPERATOR FAMILY, opcintype
1270  * isn't available, so make the user specify the types.
1271  */
1272  if (!OidIsValid(member->lefttype))
1273  member->lefttype = typeoid;
1274  if (!OidIsValid(member->righttype))
1275  member->righttype = typeoid;
1276 
1277  if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
1278  ereport(ERROR,
1279  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1280  errmsg("associated data types must be specified for index support function")));
1281 
1282  ReleaseSysCache(proctup);
1283 }
1284 
1285 /*
1286  * Add a new family member to the appropriate list, after checking for
1287  * duplicated strategy or proc number.
1288  */
1289 static void
1291 {
1292  ListCell *l;
1293 
1294  foreach(l, *list)
1295  {
1296  OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
1297 
1298  if (old->number == member->number &&
1299  old->lefttype == member->lefttype &&
1300  old->righttype == member->righttype)
1301  {
1302  if (isProc)
1303  ereport(ERROR,
1304  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1305  errmsg("function number %d for (%s,%s) appears more than once",
1306  member->number,
1307  format_type_be(member->lefttype),
1308  format_type_be(member->righttype))));
1309  else
1310  ereport(ERROR,
1311  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1312  errmsg("operator number %d for (%s,%s) appears more than once",
1313  member->number,
1314  format_type_be(member->lefttype),
1315  format_type_be(member->righttype))));
1316  }
1317  }
1318  *list = lappend(*list, member);
1319 }
1320 
1321 /*
1322  * Dump the operators to pg_amop
1323  *
1324  * We also make dependency entries in pg_depend for the opfamily entries.
1325  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1326  * else make an AUTO dependency on the opfamily.
1327  */
1328 static void
1329 storeOperators(List *opfamilyname, Oid amoid,
1330  Oid opfamilyoid, Oid opclassoid,
1331  List *operators, bool isAdd)
1332 {
1333  Relation rel;
1334  Datum values[Natts_pg_amop];
1335  bool nulls[Natts_pg_amop];
1336  HeapTuple tup;
1337  Oid entryoid;
1338  ObjectAddress myself,
1339  referenced;
1340  ListCell *l;
1341 
1342  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1343 
1344  foreach(l, operators)
1345  {
1346  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1347  char oppurpose;
1348 
1349  /*
1350  * If adding to an existing family, check for conflict with an
1351  * existing pg_amop entry (just to give a nicer error message)
1352  */
1353  if (isAdd &&
1355  ObjectIdGetDatum(opfamilyoid),
1358  Int16GetDatum(op->number)))
1359  ereport(ERROR,
1361  errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
1362  op->number,
1363  format_type_be(op->lefttype),
1365  NameListToString(opfamilyname))));
1366 
1367  oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
1368 
1369  /* Create the pg_amop entry */
1370  memset(values, 0, sizeof(values));
1371  memset(nulls, false, sizeof(nulls));
1372 
1374  Anum_pg_amop_oid);
1375  values[Anum_pg_amop_oid - 1] = ObjectIdGetDatum(entryoid);
1376  values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1377  values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
1378  values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
1379  values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
1380  values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
1381  values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
1382  values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
1383  values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
1384 
1385  tup = heap_form_tuple(rel->rd_att, values, nulls);
1386 
1387  CatalogTupleInsert(rel, tup);
1388 
1389  heap_freetuple(tup);
1390 
1391  /* Make its dependencies */
1392  myself.classId = AccessMethodOperatorRelationId;
1393  myself.objectId = entryoid;
1394  myself.objectSubId = 0;
1395 
1396  referenced.classId = OperatorRelationId;
1397  referenced.objectId = op->object;
1398  referenced.objectSubId = 0;
1399 
1400  if (OidIsValid(opclassoid))
1401  {
1402  /* if contained in an opclass, use a NORMAL dep on operator */
1403  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1404 
1405  /* ... and an INTERNAL dep on the opclass */
1406  referenced.classId = OperatorClassRelationId;
1407  referenced.objectId = opclassoid;
1408  referenced.objectSubId = 0;
1409  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1410  }
1411  else
1412  {
1413  /* if "loose" in the opfamily, use a AUTO dep on operator */
1414  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1415 
1416  /* ... and an AUTO dep on the opfamily */
1417  referenced.classId = OperatorFamilyRelationId;
1418  referenced.objectId = opfamilyoid;
1419  referenced.objectSubId = 0;
1420  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1421  }
1422 
1423  /* A search operator also needs a dep on the referenced opfamily */
1424  if (OidIsValid(op->sortfamily))
1425  {
1426  referenced.classId = OperatorFamilyRelationId;
1427  referenced.objectId = op->sortfamily;
1428  referenced.objectSubId = 0;
1429  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1430  }
1431  /* Post create hook of this access method operator */
1432  InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
1433  entryoid, 0);
1434  }
1435 
1437 }
1438 
1439 /*
1440  * Dump the procedures (support routines) to pg_amproc
1441  *
1442  * We also make dependency entries in pg_depend for the opfamily entries.
1443  * If opclassoid is valid then make an INTERNAL dependency on that opclass,
1444  * else make an AUTO dependency on the opfamily.
1445  */
1446 static void
1447 storeProcedures(List *opfamilyname, Oid amoid,
1448  Oid opfamilyoid, Oid opclassoid,
1449  List *procedures, bool isAdd)
1450 {
1451  Relation rel;
1452  Datum values[Natts_pg_amproc];
1453  bool nulls[Natts_pg_amproc];
1454  HeapTuple tup;
1455  Oid entryoid;
1456  ObjectAddress myself,
1457  referenced;
1458  ListCell *l;
1459 
1460  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1461 
1462  foreach(l, procedures)
1463  {
1464  OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
1465 
1466  /*
1467  * If adding to an existing family, check for conflict with an
1468  * existing pg_amproc entry (just to give a nicer error message)
1469  */
1470  if (isAdd &&
1472  ObjectIdGetDatum(opfamilyoid),
1473  ObjectIdGetDatum(proc->lefttype),
1474  ObjectIdGetDatum(proc->righttype),
1475  Int16GetDatum(proc->number)))
1476  ereport(ERROR,
1478  errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
1479  proc->number,
1480  format_type_be(proc->lefttype),
1481  format_type_be(proc->righttype),
1482  NameListToString(opfamilyname))));
1483 
1484  /* Create the pg_amproc entry */
1485  memset(values, 0, sizeof(values));
1486  memset(nulls, false, sizeof(nulls));
1487 
1489  Anum_pg_amproc_oid);
1490  values[Anum_pg_amproc_oid - 1] = ObjectIdGetDatum(entryoid);
1491  values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
1492  values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
1493  values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
1494  values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
1495  values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
1496 
1497  tup = heap_form_tuple(rel->rd_att, values, nulls);
1498 
1499  CatalogTupleInsert(rel, tup);
1500 
1501  heap_freetuple(tup);
1502 
1503  /* Make its dependencies */
1504  myself.classId = AccessMethodProcedureRelationId;
1505  myself.objectId = entryoid;
1506  myself.objectSubId = 0;
1507 
1508  referenced.classId = ProcedureRelationId;
1509  referenced.objectId = proc->object;
1510  referenced.objectSubId = 0;
1511 
1512  if (OidIsValid(opclassoid))
1513  {
1514  /* if contained in an opclass, use a NORMAL dep on procedure */
1515  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1516 
1517  /* ... and an INTERNAL dep on the opclass */
1518  referenced.classId = OperatorClassRelationId;
1519  referenced.objectId = opclassoid;
1520  referenced.objectSubId = 0;
1521  recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
1522  }
1523  else
1524  {
1525  /* if "loose" in the opfamily, use a AUTO dep on procedure */
1526  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1527 
1528  /* ... and an AUTO dep on the opfamily */
1529  referenced.classId = OperatorFamilyRelationId;
1530  referenced.objectId = opfamilyoid;
1531  referenced.objectSubId = 0;
1532  recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1533  }
1534  /* Post create hook of access method procedure */
1535  InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
1536  entryoid, 0);
1537  }
1538 
1540 }
1541 
1542 
1543 /*
1544  * Remove operator entries from an opfamily.
1545  *
1546  * Note: this is only allowed for "loose" members of an opfamily, hence
1547  * behavior is always RESTRICT.
1548  */
1549 static void
1550 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1551  List *operators)
1552 {
1553  ListCell *l;
1554 
1555  foreach(l, operators)
1556  {
1557  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1558  Oid amopid;
1559  ObjectAddress object;
1560 
1561  amopid = GetSysCacheOid4(AMOPSTRATEGY, Anum_pg_amop_oid,
1562  ObjectIdGetDatum(opfamilyoid),
1565  Int16GetDatum(op->number));
1566  if (!OidIsValid(amopid))
1567  ereport(ERROR,
1568  (errcode(ERRCODE_UNDEFINED_OBJECT),
1569  errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
1570  op->number,
1571  format_type_be(op->lefttype),
1573  NameListToString(opfamilyname))));
1574 
1575  object.classId = AccessMethodOperatorRelationId;
1576  object.objectId = amopid;
1577  object.objectSubId = 0;
1578 
1579  performDeletion(&object, DROP_RESTRICT, 0);
1580  }
1581 }
1582 
1583 /*
1584  * Remove procedure entries from an opfamily.
1585  *
1586  * Note: this is only allowed for "loose" members of an opfamily, hence
1587  * behavior is always RESTRICT.
1588  */
1589 static void
1590 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
1591  List *procedures)
1592 {
1593  ListCell *l;
1594 
1595  foreach(l, procedures)
1596  {
1597  OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
1598  Oid amprocid;
1599  ObjectAddress object;
1600 
1601  amprocid = GetSysCacheOid4(AMPROCNUM, Anum_pg_amproc_oid,
1602  ObjectIdGetDatum(opfamilyoid),
1605  Int16GetDatum(op->number));
1606  if (!OidIsValid(amprocid))
1607  ereport(ERROR,
1608  (errcode(ERRCODE_UNDEFINED_OBJECT),
1609  errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
1610  op->number,
1611  format_type_be(op->lefttype),
1613  NameListToString(opfamilyname))));
1614 
1615  object.classId = AccessMethodProcedureRelationId;
1616  object.objectId = amprocid;
1617  object.objectSubId = 0;
1618 
1619  performDeletion(&object, DROP_RESTRICT, 0);
1620  }
1621 }
1622 
1623 /*
1624  * Deletion subroutines for use by dependency.c.
1625  */
1626 void
1628 {
1629  Relation rel;
1630  HeapTuple tup;
1631 
1632  rel = table_open(OperatorFamilyRelationId, RowExclusiveLock);
1633 
1634  tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
1635  if (!HeapTupleIsValid(tup)) /* should not happen */
1636  elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
1637 
1638  CatalogTupleDelete(rel, &tup->t_self);
1639 
1640  ReleaseSysCache(tup);
1641 
1643 }
1644 
1645 void
1647 {
1648  Relation rel;
1649  HeapTuple tup;
1650 
1651  rel = table_open(OperatorClassRelationId, RowExclusiveLock);
1652 
1653  tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
1654  if (!HeapTupleIsValid(tup)) /* should not happen */
1655  elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
1656 
1657  CatalogTupleDelete(rel, &tup->t_self);
1658 
1659  ReleaseSysCache(tup);
1660 
1662 }
1663 
1664 void
1666 {
1667  Relation rel;
1668  HeapTuple tup;
1669  ScanKeyData skey[1];
1670  SysScanDesc scan;
1671 
1672  ScanKeyInit(&skey[0],
1673  Anum_pg_amop_oid,
1674  BTEqualStrategyNumber, F_OIDEQ,
1675  ObjectIdGetDatum(entryOid));
1676 
1677  rel = table_open(AccessMethodOperatorRelationId, RowExclusiveLock);
1678 
1680  NULL, 1, skey);
1681 
1682  /* we expect exactly one match */
1683  tup = systable_getnext(scan);
1684  if (!HeapTupleIsValid(tup))
1685  elog(ERROR, "could not find tuple for amop entry %u", entryOid);
1686 
1687  CatalogTupleDelete(rel, &tup->t_self);
1688 
1689  systable_endscan(scan);
1691 }
1692 
1693 void
1695 {
1696  Relation rel;
1697  HeapTuple tup;
1698  ScanKeyData skey[1];
1699  SysScanDesc scan;
1700 
1701  ScanKeyInit(&skey[0],
1702  Anum_pg_amproc_oid,
1703  BTEqualStrategyNumber, F_OIDEQ,
1704  ObjectIdGetDatum(entryOid));
1705 
1706  rel = table_open(AccessMethodProcedureRelationId, RowExclusiveLock);
1707 
1709  NULL, 1, skey);
1710 
1711  /* we expect exactly one match */
1712  tup = systable_getnext(scan);
1713  if (!HeapTupleIsValid(tup))
1714  elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
1715 
1716  CatalogTupleDelete(rel, &tup->t_self);
1717 
1718  systable_endscan(scan);
1720 }
1721 
1722 /*
1723  * Subroutine for ALTER OPERATOR CLASS SET SCHEMA/RENAME
1724  *
1725  * Is there an operator class with the given name and signature already
1726  * in the given namespace? If so, raise an appropriate error message.
1727  */
1728 void
1729 IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
1730  Oid opcnamespace)
1731 {
1732  /* make sure the new name doesn't exist */
1734  ObjectIdGetDatum(opcmethod),
1735  CStringGetDatum(opcname),
1736  ObjectIdGetDatum(opcnamespace)))
1737  ereport(ERROR,
1739  errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1740  opcname,
1741  get_am_name(opcmethod),
1742  get_namespace_name(opcnamespace))));
1743 }
1744 
1745 /*
1746  * Subroutine for ALTER OPERATOR FAMILY SET SCHEMA/RENAME
1747  *
1748  * Is there an operator family with the given name and signature already
1749  * in the given namespace? If so, raise an appropriate error message.
1750  */
1751 void
1752 IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
1753  Oid opfnamespace)
1754 {
1755  /* make sure the new name doesn't exist */
1757  ObjectIdGetDatum(opfmethod),
1758  CStringGetDatum(opfname),
1759  ObjectIdGetDatum(opfnamespace)))
1760  ereport(ERROR,
1762  errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
1763  opfname,
1764  get_am_name(opfmethod),
1765  get_namespace_name(opfnamespace))));
1766 }
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:317
#define NameGetDatum(X)
Definition: postgres.h:595
uint16 amsupport
Definition: amapi.h:173
#define BTORDER_PROC
Definition: nbtree.h:586
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
Oid LookupExplicitNamespace(const char *nspname, bool missing_ok)
Definition: namespace.c:2893
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
Definition: opclasscmds.c:1066
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
Definition: syscache.h:36
#define BTEQUALIMAGE_PROC
Definition: nbtree.h:589
#define BTSORTSUPPORT_PROC
Definition: nbtree.h:587
void RemoveOpClassById(Oid opclassOid)
Definition: opclasscmds.c:1646
Oid GetUserId(void)
Definition: miscinit.c:439
TypeName * storedtype
Definition: parsenodes.h:2616
bool amcanorderbyop
Definition: amapi.h:177
Oid QualifiedNameGetCreationNamespace(List *names, char **objname_p)
Definition: namespace.c:2995
#define PointerGetDatum(X)
Definition: postgres.h:556
char * TypeNameToString(const TypeName *typeName)
Definition: parse_type.c:476
static HeapTuple OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
Definition: opclasscmds.c:164
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:4805
int errcode(int sqlerrcode)
Definition: elog.c:610
static HeapTuple OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:83
static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *procedures)
Definition: opclasscmds.c:1590
#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:327
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:2809
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:222
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
void RemoveAmProcEntryById(Oid entryOid)
Definition: opclasscmds.c:1694
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:4779
ObjectAddress DefineOpClass(CreateOpClassStmt *stmt)
Definition: opclasscmds.c:330
int namestrcpy(Name name, const char *str)
Definition: name.c:250
Oid OpclassnameGetOpcid(Oid amid, const char *opcname)
Definition: namespace.c:1800
#define OidIsValid(objectId)
Definition: c.h:644
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4691
void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, Oid opcnamespace)
Definition: opclasscmds.c:1729
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
#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:3665
#define AccessMethodProcedureOidIndexId
Definition: indexing.h:86
#define OPCLASS_ITEM_OPERATOR
Definition: parsenodes.h:2602
char * get_opname(Oid opno)
Definition: lsyscache.c:1143
static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, List *operators)
Definition: opclasscmds.c:1550
Oid member
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
Oid OpfamilynameGetOpfid(Oid amid, const char *opfname)
Definition: namespace.c:1883
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
static void AlterOpFamilyDrop(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid, int maxOpNumber, int maxProcNumber, List *items)
Definition: opclasscmds.c:961
#define linitial(l)
Definition: pg_list.h:195
#define BTINRANGE_PROC
Definition: nbtree.h:588
#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:1436
HeapTuple SearchSysCache3(int cacheId, Datum key1, Datum key2, Datum key3)
Definition: syscache.c:1138
ItemPointerData t_self
Definition: htup.h:65
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Definition: c.h:609
TypeName * datatype
Definition: parsenodes.h:2597
void RemoveOpFamilyById(Oid opfamilyOid)
Definition: opclasscmds.c:1627
ObjectWithArgs * name
Definition: parsenodes.h:2610
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3120
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:957
static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
Definition: opclasscmds.c:1290
#define CStringGetDatum(X)
Definition: postgres.h:578
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:316
#define HASHSTANDARD_PROC
Definition: hash.h:353
static ObjectAddress CreateOpFamily(const char *amname, const char *opfname, Oid namespaceoid, Oid amoid)
Definition: opclasscmds.c:245
void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid, List *operators, List *procedures)
List * lappend(List *list, void *datum)
Definition: list.c:322
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1116
char * NameListToString(List *names)
Definition: namespace.c:3102
void RemoveAmOpEntryById(Oid entryOid)
Definition: opclasscmds.c:1665
static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
Definition: opclasscmds.c:1037
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:51
void * palloc0(Size size)
Definition: mcxt.c:980
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
TupleDesc rd_att
Definition: rel.h:90
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:133
#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:1118
#define ereport(elevel,...)
Definition: elog.h:144
#define OPCLASS_ITEM_FUNCTION
Definition: parsenodes.h:2603
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:738
#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:836
#define OPCLASS_ITEM_STORAGETYPE
Definition: parsenodes.h:2604
void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid, List *operators, List *procedures)
Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
Definition: opclasscmds.c:141
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:1447
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:775
ObjectAddress DefineOpFamily(CreateOpFamilyStmt *stmt)
Definition: opclasscmds.c:730
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:824
#define elog(elevel,...)
Definition: elog.h:214
Oid LookupFuncWithArgs(ObjectType objtype, ObjectWithArgs *func, bool missing_ok)
Definition: parse_func.c:2163
#define NameStr(name)
Definition: c.h:615
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:1132
static void storeOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid, Oid opclassoid, List *operators, bool isAdd)
Definition: opclasscmds.c:1329
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:31
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:4831
void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, Oid opfnamespace)
Definition: opclasscmds.c:1752
#define OpfamilyOidIndexId
Definition: indexing.h:207
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291