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