00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include <limits.h>
00019
00020 #include "access/genam.h"
00021 #include "access/heapam.h"
00022 #include "access/nbtree.h"
00023 #include "access/htup_details.h"
00024 #include "access/sysattr.h"
00025 #include "catalog/dependency.h"
00026 #include "catalog/indexing.h"
00027 #include "catalog/objectaccess.h"
00028 #include "catalog/pg_amop.h"
00029 #include "catalog/pg_amproc.h"
00030 #include "catalog/pg_namespace.h"
00031 #include "catalog/pg_opclass.h"
00032 #include "catalog/pg_operator.h"
00033 #include "catalog/pg_opfamily.h"
00034 #include "catalog/pg_proc.h"
00035 #include "catalog/pg_type.h"
00036 #include "commands/alter.h"
00037 #include "commands/defrem.h"
00038 #include "miscadmin.h"
00039 #include "parser/parse_func.h"
00040 #include "parser/parse_oper.h"
00041 #include "parser/parse_type.h"
00042 #include "utils/builtins.h"
00043 #include "utils/fmgroids.h"
00044 #include "utils/lsyscache.h"
00045 #include "utils/rel.h"
00046 #include "utils/syscache.h"
00047 #include "utils/tqual.h"
00048
00049
00050
00051
00052
00053
00054 typedef struct
00055 {
00056 Oid object;
00057 int number;
00058 Oid lefttype;
00059 Oid righttype;
00060 Oid sortfamily;
00061 } OpFamilyMember;
00062
00063
00064 static void AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00065 int maxOpNumber, int maxProcNumber,
00066 List *items);
00067 static void AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00068 int maxOpNumber, int maxProcNumber,
00069 List *items);
00070 static void processTypesSpec(List *args, Oid *lefttype, Oid *righttype);
00071 static void assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
00072 static void assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid);
00073 static void addFamilyMember(List **list, OpFamilyMember *member, bool isProc);
00074 static void storeOperators(List *opfamilyname, Oid amoid,
00075 Oid opfamilyoid, Oid opclassoid,
00076 List *operators, bool isAdd);
00077 static void storeProcedures(List *opfamilyname, Oid amoid,
00078 Oid opfamilyoid, Oid opclassoid,
00079 List *procedures, bool isAdd);
00080 static void dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00081 List *operators);
00082 static void dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00083 List *procedures);
00084
00085
00086
00087
00088
00089
00090
00091 static HeapTuple
00092 OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
00093 {
00094 char *schemaname;
00095 char *opfname;
00096 HeapTuple htup;
00097
00098
00099 DeconstructQualifiedName(opfamilyname, &schemaname, &opfname);
00100
00101 if (schemaname)
00102 {
00103
00104 Oid namespaceId;
00105
00106 namespaceId = LookupExplicitNamespace(schemaname, false);
00107 htup = SearchSysCache3(OPFAMILYAMNAMENSP,
00108 ObjectIdGetDatum(amID),
00109 PointerGetDatum(opfname),
00110 ObjectIdGetDatum(namespaceId));
00111 }
00112 else
00113 {
00114
00115 Oid opfID = OpfamilynameGetOpfid(amID, opfname);
00116
00117 if (!OidIsValid(opfID))
00118 htup = NULL;
00119 else
00120 htup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfID));
00121 }
00122
00123 if (!HeapTupleIsValid(htup) && !missing_ok)
00124 {
00125 HeapTuple amtup;
00126
00127 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
00128 if (!HeapTupleIsValid(amtup))
00129 elog(ERROR, "cache lookup failed for access method %u", amID);
00130 ereport(ERROR,
00131 (errcode(ERRCODE_UNDEFINED_OBJECT),
00132 errmsg("operator family \"%s\" does not exist for access method \"%s\"",
00133 NameListToString(opfamilyname),
00134 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
00135 }
00136
00137 return htup;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146 Oid
00147 get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok)
00148 {
00149 HeapTuple htup;
00150 Oid opfID;
00151
00152 htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
00153 if (!HeapTupleIsValid(htup))
00154 return InvalidOid;
00155 opfID = HeapTupleGetOid(htup);
00156 ReleaseSysCache(htup);
00157
00158 return opfID;
00159 }
00160
00161
00162
00163
00164
00165
00166
00167 static HeapTuple
00168 OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
00169 {
00170 char *schemaname;
00171 char *opcname;
00172 HeapTuple htup;
00173
00174
00175 DeconstructQualifiedName(opclassname, &schemaname, &opcname);
00176
00177 if (schemaname)
00178 {
00179
00180 Oid namespaceId;
00181
00182 namespaceId = LookupExplicitNamespace(schemaname, false);
00183 htup = SearchSysCache3(CLAAMNAMENSP,
00184 ObjectIdGetDatum(amID),
00185 PointerGetDatum(opcname),
00186 ObjectIdGetDatum(namespaceId));
00187 }
00188 else
00189 {
00190
00191 Oid opcID = OpclassnameGetOpcid(amID, opcname);
00192
00193 if (!OidIsValid(opcID))
00194 htup = NULL;
00195 else
00196 htup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcID));
00197 }
00198
00199 if (!HeapTupleIsValid(htup) && !missing_ok)
00200 {
00201 HeapTuple amtup;
00202
00203 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amID));
00204 if (!HeapTupleIsValid(amtup))
00205 elog(ERROR, "cache lookup failed for access method %u", amID);
00206 ereport(ERROR,
00207 (errcode(ERRCODE_UNDEFINED_OBJECT),
00208 errmsg("operator class \"%s\" does not exist for access method \"%s\"",
00209 NameListToString(opclassname),
00210 NameStr(((Form_pg_am) GETSTRUCT(amtup))->amname))));
00211 }
00212
00213 return htup;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222 Oid
00223 get_opclass_oid(Oid amID, List *opclassname, bool missing_ok)
00224 {
00225 HeapTuple htup;
00226 Oid opcID;
00227
00228 htup = OpClassCacheLookup(amID, opclassname, missing_ok);
00229 if (!HeapTupleIsValid(htup))
00230 return InvalidOid;
00231 opcID = HeapTupleGetOid(htup);
00232 ReleaseSysCache(htup);
00233
00234 return opcID;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243 static Oid
00244 CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
00245 {
00246 Oid opfamilyoid;
00247 Relation rel;
00248 HeapTuple tup;
00249 Datum values[Natts_pg_opfamily];
00250 bool nulls[Natts_pg_opfamily];
00251 NameData opfName;
00252 ObjectAddress myself,
00253 referenced;
00254
00255 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
00256
00257
00258
00259
00260
00261 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
00262 ObjectIdGetDatum(amoid),
00263 CStringGetDatum(opfname),
00264 ObjectIdGetDatum(namespaceoid)))
00265 ereport(ERROR,
00266 (errcode(ERRCODE_DUPLICATE_OBJECT),
00267 errmsg("operator family \"%s\" for access method \"%s\" already exists",
00268 opfname, amname)));
00269
00270
00271
00272
00273 memset(values, 0, sizeof(values));
00274 memset(nulls, false, sizeof(nulls));
00275
00276 values[Anum_pg_opfamily_opfmethod - 1] = ObjectIdGetDatum(amoid);
00277 namestrcpy(&opfName, opfname);
00278 values[Anum_pg_opfamily_opfname - 1] = NameGetDatum(&opfName);
00279 values[Anum_pg_opfamily_opfnamespace - 1] = ObjectIdGetDatum(namespaceoid);
00280 values[Anum_pg_opfamily_opfowner - 1] = ObjectIdGetDatum(GetUserId());
00281
00282 tup = heap_form_tuple(rel->rd_att, values, nulls);
00283
00284 opfamilyoid = simple_heap_insert(rel, tup);
00285
00286 CatalogUpdateIndexes(rel, tup);
00287
00288 heap_freetuple(tup);
00289
00290
00291
00292
00293
00294
00295 myself.classId = OperatorFamilyRelationId;
00296 myself.objectId = opfamilyoid;
00297 myself.objectSubId = 0;
00298
00299
00300 referenced.classId = NamespaceRelationId;
00301 referenced.objectId = namespaceoid;
00302 referenced.objectSubId = 0;
00303 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00304
00305
00306 recordDependencyOnOwner(OperatorFamilyRelationId, opfamilyoid, GetUserId());
00307
00308
00309 recordDependencyOnCurrentExtension(&myself, false);
00310
00311
00312 InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
00313
00314 heap_close(rel, RowExclusiveLock);
00315
00316 return opfamilyoid;
00317 }
00318
00319
00320
00321
00322
00323 Oid
00324 DefineOpClass(CreateOpClassStmt *stmt)
00325 {
00326 char *opcname;
00327 Oid amoid,
00328 typeoid,
00329 storageoid,
00330 namespaceoid,
00331 opfamilyoid,
00332 opclassoid;
00333 int maxOpNumber,
00334 maxProcNumber;
00335 bool amstorage;
00336 List *operators;
00337 List *procedures;
00338 ListCell *l;
00339 Relation rel;
00340 HeapTuple tup;
00341 Form_pg_am pg_am;
00342 Datum values[Natts_pg_opclass];
00343 bool nulls[Natts_pg_opclass];
00344 AclResult aclresult;
00345 NameData opcName;
00346 ObjectAddress myself,
00347 referenced;
00348
00349
00350 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
00351 &opcname);
00352
00353
00354 aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
00355 if (aclresult != ACLCHECK_OK)
00356 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00357 get_namespace_name(namespaceoid));
00358
00359
00360 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
00361 if (!HeapTupleIsValid(tup))
00362 ereport(ERROR,
00363 (errcode(ERRCODE_UNDEFINED_OBJECT),
00364 errmsg("access method \"%s\" does not exist",
00365 stmt->amname)));
00366
00367 amoid = HeapTupleGetOid(tup);
00368 pg_am = (Form_pg_am) GETSTRUCT(tup);
00369 maxOpNumber = pg_am->amstrategies;
00370
00371 if (maxOpNumber <= 0)
00372 maxOpNumber = SHRT_MAX;
00373 maxProcNumber = pg_am->amsupport;
00374 amstorage = pg_am->amstorage;
00375
00376
00377
00378 ReleaseSysCache(tup);
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 if (!superuser())
00401 ereport(ERROR,
00402 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00403 errmsg("must be superuser to create an operator class")));
00404
00405
00406 typeoid = typenameTypeId(NULL, stmt->datatype);
00407
00408 #ifdef NOT_USED
00409
00410
00411 if (!pg_type_ownercheck(typeoid, GetUserId()))
00412 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid);
00413 #endif
00414
00415
00416
00417
00418
00419 if (stmt->opfamilyname)
00420 {
00421 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
00422 }
00423 else
00424 {
00425
00426 tup = SearchSysCache3(OPFAMILYAMNAMENSP,
00427 ObjectIdGetDatum(amoid),
00428 PointerGetDatum(opcname),
00429 ObjectIdGetDatum(namespaceoid));
00430 if (HeapTupleIsValid(tup))
00431 {
00432 opfamilyoid = HeapTupleGetOid(tup);
00433
00434
00435
00436
00437
00438 ReleaseSysCache(tup);
00439 }
00440 else
00441 {
00442
00443
00444
00445 opfamilyoid = CreateOpFamily(stmt->amname, opcname,
00446 namespaceoid, amoid);
00447 }
00448 }
00449
00450 operators = NIL;
00451 procedures = NIL;
00452
00453
00454 storageoid = InvalidOid;
00455
00456
00457
00458
00459 foreach(l, stmt->items)
00460 {
00461 CreateOpClassItem *item = lfirst(l);
00462 Oid operOid;
00463 Oid funcOid;
00464 Oid sortfamilyOid;
00465 OpFamilyMember *member;
00466
00467 Assert(IsA(item, CreateOpClassItem));
00468 switch (item->itemtype)
00469 {
00470 case OPCLASS_ITEM_OPERATOR:
00471 if (item->number <= 0 || item->number > maxOpNumber)
00472 ereport(ERROR,
00473 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00474 errmsg("invalid operator number %d,"
00475 " must be between 1 and %d",
00476 item->number, maxOpNumber)));
00477 if (item->args != NIL)
00478 {
00479 TypeName *typeName1 = (TypeName *) linitial(item->args);
00480 TypeName *typeName2 = (TypeName *) lsecond(item->args);
00481
00482 operOid = LookupOperNameTypeNames(NULL, item->name,
00483 typeName1, typeName2,
00484 false, -1);
00485 }
00486 else
00487 {
00488
00489 operOid = LookupOperName(NULL, item->name,
00490 typeoid, typeoid,
00491 false, -1);
00492 }
00493
00494 if (item->order_family)
00495 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
00496 item->order_family,
00497 false);
00498 else
00499 sortfamilyOid = InvalidOid;
00500
00501 #ifdef NOT_USED
00502
00503
00504 if (!pg_oper_ownercheck(operOid, GetUserId()))
00505 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
00506 get_opname(operOid));
00507 funcOid = get_opcode(operOid);
00508 if (!pg_proc_ownercheck(funcOid, GetUserId()))
00509 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00510 get_func_name(funcOid));
00511 #endif
00512
00513
00514 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
00515 member->object = operOid;
00516 member->number = item->number;
00517 member->sortfamily = sortfamilyOid;
00518 assignOperTypes(member, amoid, typeoid);
00519 addFamilyMember(&operators, member, false);
00520 break;
00521 case OPCLASS_ITEM_FUNCTION:
00522 if (item->number <= 0 || item->number > maxProcNumber)
00523 ereport(ERROR,
00524 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00525 errmsg("invalid procedure number %d,"
00526 " must be between 1 and %d",
00527 item->number, maxProcNumber)));
00528 funcOid = LookupFuncNameTypeNames(item->name, item->args,
00529 false);
00530 #ifdef NOT_USED
00531
00532
00533 if (!pg_proc_ownercheck(funcOid, GetUserId()))
00534 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00535 get_func_name(funcOid));
00536 #endif
00537
00538
00539 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
00540 member->object = funcOid;
00541 member->number = item->number;
00542
00543
00544 if (item->class_args)
00545 processTypesSpec(item->class_args,
00546 &member->lefttype, &member->righttype);
00547
00548 assignProcTypes(member, amoid, typeoid);
00549 addFamilyMember(&procedures, member, true);
00550 break;
00551 case OPCLASS_ITEM_STORAGETYPE:
00552 if (OidIsValid(storageoid))
00553 ereport(ERROR,
00554 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00555 errmsg("storage type specified more than once")));
00556 storageoid = typenameTypeId(NULL, item->storedtype);
00557
00558 #ifdef NOT_USED
00559
00560
00561 if (!pg_type_ownercheck(storageoid, GetUserId()))
00562 aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid);
00563 #endif
00564 break;
00565 default:
00566 elog(ERROR, "unrecognized item type: %d", item->itemtype);
00567 break;
00568 }
00569 }
00570
00571
00572
00573
00574 if (OidIsValid(storageoid))
00575 {
00576
00577 if (storageoid == typeoid)
00578 storageoid = InvalidOid;
00579 else if (!amstorage)
00580 ereport(ERROR,
00581 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00582 errmsg("storage type cannot be different from data type for access method \"%s\"",
00583 stmt->amname)));
00584 }
00585
00586 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
00587
00588
00589
00590
00591
00592 if (SearchSysCacheExists3(CLAAMNAMENSP,
00593 ObjectIdGetDatum(amoid),
00594 CStringGetDatum(opcname),
00595 ObjectIdGetDatum(namespaceoid)))
00596 ereport(ERROR,
00597 (errcode(ERRCODE_DUPLICATE_OBJECT),
00598 errmsg("operator class \"%s\" for access method \"%s\" already exists",
00599 opcname, stmt->amname)));
00600
00601
00602
00603
00604
00605
00606 if (stmt->isDefault)
00607 {
00608 ScanKeyData skey[1];
00609 SysScanDesc scan;
00610
00611 ScanKeyInit(&skey[0],
00612 Anum_pg_opclass_opcmethod,
00613 BTEqualStrategyNumber, F_OIDEQ,
00614 ObjectIdGetDatum(amoid));
00615
00616 scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
00617 SnapshotNow, 1, skey);
00618
00619 while (HeapTupleIsValid(tup = systable_getnext(scan)))
00620 {
00621 Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);
00622
00623 if (opclass->opcintype == typeoid && opclass->opcdefault)
00624 ereport(ERROR,
00625 (errcode(ERRCODE_DUPLICATE_OBJECT),
00626 errmsg("could not make operator class \"%s\" be default for type %s",
00627 opcname,
00628 TypeNameToString(stmt->datatype)),
00629 errdetail("Operator class \"%s\" already is the default.",
00630 NameStr(opclass->opcname))));
00631 }
00632
00633 systable_endscan(scan);
00634 }
00635
00636
00637
00638
00639 memset(values, 0, sizeof(values));
00640 memset(nulls, false, sizeof(nulls));
00641
00642 values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
00643 namestrcpy(&opcName, opcname);
00644 values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
00645 values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
00646 values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
00647 values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
00648 values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
00649 values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
00650 values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);
00651
00652 tup = heap_form_tuple(rel->rd_att, values, nulls);
00653
00654 opclassoid = simple_heap_insert(rel, tup);
00655
00656 CatalogUpdateIndexes(rel, tup);
00657
00658 heap_freetuple(tup);
00659
00660
00661
00662
00663
00664 storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
00665 opclassoid, operators, false);
00666 storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
00667 opclassoid, procedures, false);
00668
00669
00670
00671
00672
00673
00674 myself.classId = OperatorClassRelationId;
00675 myself.objectId = opclassoid;
00676 myself.objectSubId = 0;
00677
00678
00679 referenced.classId = NamespaceRelationId;
00680 referenced.objectId = namespaceoid;
00681 referenced.objectSubId = 0;
00682 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00683
00684
00685 referenced.classId = OperatorFamilyRelationId;
00686 referenced.objectId = opfamilyoid;
00687 referenced.objectSubId = 0;
00688 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
00689
00690
00691 referenced.classId = TypeRelationId;
00692 referenced.objectId = typeoid;
00693 referenced.objectSubId = 0;
00694 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00695
00696
00697 if (OidIsValid(storageoid))
00698 {
00699 referenced.classId = TypeRelationId;
00700 referenced.objectId = storageoid;
00701 referenced.objectSubId = 0;
00702 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00703 }
00704
00705
00706 recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());
00707
00708
00709 recordDependencyOnCurrentExtension(&myself, false);
00710
00711
00712 InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
00713
00714 heap_close(rel, RowExclusiveLock);
00715
00716 return opclassoid;
00717 }
00718
00719
00720
00721
00722
00723
00724 Oid
00725 DefineOpFamily(CreateOpFamilyStmt *stmt)
00726 {
00727 char *opfname;
00728 Oid amoid,
00729 namespaceoid;
00730 AclResult aclresult;
00731
00732
00733 namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
00734 &opfname);
00735
00736
00737 aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
00738 if (aclresult != ACLCHECK_OK)
00739 aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
00740 get_namespace_name(namespaceoid));
00741
00742
00743 amoid = get_am_oid(stmt->amname, false);
00744
00745
00746
00747
00748
00749
00750
00751 if (!superuser())
00752 ereport(ERROR,
00753 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00754 errmsg("must be superuser to create an operator family")));
00755
00756
00757 return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 Oid
00770 AlterOpFamily(AlterOpFamilyStmt *stmt)
00771 {
00772 Oid amoid,
00773 opfamilyoid;
00774 int maxOpNumber,
00775 maxProcNumber;
00776 HeapTuple tup;
00777 Form_pg_am pg_am;
00778
00779
00780 tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
00781 if (!HeapTupleIsValid(tup))
00782 ereport(ERROR,
00783 (errcode(ERRCODE_UNDEFINED_OBJECT),
00784 errmsg("access method \"%s\" does not exist",
00785 stmt->amname)));
00786
00787 amoid = HeapTupleGetOid(tup);
00788 pg_am = (Form_pg_am) GETSTRUCT(tup);
00789 maxOpNumber = pg_am->amstrategies;
00790
00791 if (maxOpNumber <= 0)
00792 maxOpNumber = SHRT_MAX;
00793 maxProcNumber = pg_am->amsupport;
00794
00795
00796
00797 ReleaseSysCache(tup);
00798
00799
00800 opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
00801
00802
00803
00804
00805
00806
00807 if (!superuser())
00808 ereport(ERROR,
00809 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00810 errmsg("must be superuser to alter an operator family")));
00811
00812
00813
00814
00815 if (stmt->isDrop)
00816 AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
00817 maxOpNumber, maxProcNumber,
00818 stmt->items);
00819 else
00820 AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
00821 maxOpNumber, maxProcNumber,
00822 stmt->items);
00823
00824 return opfamilyoid;
00825 }
00826
00827
00828
00829
00830 static void
00831 AlterOpFamilyAdd(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00832 int maxOpNumber, int maxProcNumber,
00833 List *items)
00834 {
00835 List *operators;
00836 List *procedures;
00837 ListCell *l;
00838
00839 operators = NIL;
00840 procedures = NIL;
00841
00842
00843
00844
00845 foreach(l, items)
00846 {
00847 CreateOpClassItem *item = lfirst(l);
00848 Oid operOid;
00849 Oid funcOid;
00850 Oid sortfamilyOid;
00851 OpFamilyMember *member;
00852
00853 Assert(IsA(item, CreateOpClassItem));
00854 switch (item->itemtype)
00855 {
00856 case OPCLASS_ITEM_OPERATOR:
00857 if (item->number <= 0 || item->number > maxOpNumber)
00858 ereport(ERROR,
00859 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00860 errmsg("invalid operator number %d,"
00861 " must be between 1 and %d",
00862 item->number, maxOpNumber)));
00863 if (item->args != NIL)
00864 {
00865 TypeName *typeName1 = (TypeName *) linitial(item->args);
00866 TypeName *typeName2 = (TypeName *) lsecond(item->args);
00867
00868 operOid = LookupOperNameTypeNames(NULL, item->name,
00869 typeName1, typeName2,
00870 false, -1);
00871 }
00872 else
00873 {
00874 ereport(ERROR,
00875 (errcode(ERRCODE_SYNTAX_ERROR),
00876 errmsg("operator argument types must be specified in ALTER OPERATOR FAMILY")));
00877 operOid = InvalidOid;
00878 }
00879
00880 if (item->order_family)
00881 sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
00882 item->order_family,
00883 false);
00884 else
00885 sortfamilyOid = InvalidOid;
00886
00887 #ifdef NOT_USED
00888
00889
00890 if (!pg_oper_ownercheck(operOid, GetUserId()))
00891 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
00892 get_opname(operOid));
00893 funcOid = get_opcode(operOid);
00894 if (!pg_proc_ownercheck(funcOid, GetUserId()))
00895 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00896 get_func_name(funcOid));
00897 #endif
00898
00899
00900 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
00901 member->object = operOid;
00902 member->number = item->number;
00903 member->sortfamily = sortfamilyOid;
00904 assignOperTypes(member, amoid, InvalidOid);
00905 addFamilyMember(&operators, member, false);
00906 break;
00907 case OPCLASS_ITEM_FUNCTION:
00908 if (item->number <= 0 || item->number > maxProcNumber)
00909 ereport(ERROR,
00910 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00911 errmsg("invalid procedure number %d,"
00912 " must be between 1 and %d",
00913 item->number, maxProcNumber)));
00914 funcOid = LookupFuncNameTypeNames(item->name, item->args,
00915 false);
00916 #ifdef NOT_USED
00917
00918
00919 if (!pg_proc_ownercheck(funcOid, GetUserId()))
00920 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
00921 get_func_name(funcOid));
00922 #endif
00923
00924
00925 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
00926 member->object = funcOid;
00927 member->number = item->number;
00928
00929
00930 if (item->class_args)
00931 processTypesSpec(item->class_args,
00932 &member->lefttype, &member->righttype);
00933
00934 assignProcTypes(member, amoid, InvalidOid);
00935 addFamilyMember(&procedures, member, true);
00936 break;
00937 case OPCLASS_ITEM_STORAGETYPE:
00938 ereport(ERROR,
00939 (errcode(ERRCODE_SYNTAX_ERROR),
00940 errmsg("STORAGE cannot be specified in ALTER OPERATOR FAMILY")));
00941 break;
00942 default:
00943 elog(ERROR, "unrecognized item type: %d", item->itemtype);
00944 break;
00945 }
00946 }
00947
00948
00949
00950
00951
00952 storeOperators(opfamilyname, amoid, opfamilyoid,
00953 InvalidOid, operators, true);
00954 storeProcedures(opfamilyname, amoid, opfamilyoid,
00955 InvalidOid, procedures, true);
00956 }
00957
00958
00959
00960
00961 static void
00962 AlterOpFamilyDrop(List *opfamilyname, Oid amoid, Oid opfamilyoid,
00963 int maxOpNumber, int maxProcNumber,
00964 List *items)
00965 {
00966 List *operators;
00967 List *procedures;
00968 ListCell *l;
00969
00970 operators = NIL;
00971 procedures = NIL;
00972
00973
00974
00975
00976 foreach(l, items)
00977 {
00978 CreateOpClassItem *item = lfirst(l);
00979 Oid lefttype,
00980 righttype;
00981 OpFamilyMember *member;
00982
00983 Assert(IsA(item, CreateOpClassItem));
00984 switch (item->itemtype)
00985 {
00986 case OPCLASS_ITEM_OPERATOR:
00987 if (item->number <= 0 || item->number > maxOpNumber)
00988 ereport(ERROR,
00989 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
00990 errmsg("invalid operator number %d,"
00991 " must be between 1 and %d",
00992 item->number, maxOpNumber)));
00993 processTypesSpec(item->args, &lefttype, &righttype);
00994
00995 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
00996 member->number = item->number;
00997 member->lefttype = lefttype;
00998 member->righttype = righttype;
00999 addFamilyMember(&operators, member, false);
01000 break;
01001 case OPCLASS_ITEM_FUNCTION:
01002 if (item->number <= 0 || item->number > maxProcNumber)
01003 ereport(ERROR,
01004 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01005 errmsg("invalid procedure number %d,"
01006 " must be between 1 and %d",
01007 item->number, maxProcNumber)));
01008 processTypesSpec(item->args, &lefttype, &righttype);
01009
01010 member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
01011 member->number = item->number;
01012 member->lefttype = lefttype;
01013 member->righttype = righttype;
01014 addFamilyMember(&procedures, member, true);
01015 break;
01016 case OPCLASS_ITEM_STORAGETYPE:
01017
01018 default:
01019 elog(ERROR, "unrecognized item type: %d", item->itemtype);
01020 break;
01021 }
01022 }
01023
01024
01025
01026
01027 dropOperators(opfamilyname, amoid, opfamilyoid, operators);
01028 dropProcedures(opfamilyname, amoid, opfamilyoid, procedures);
01029 }
01030
01031
01032
01033
01034
01035 static void
01036 processTypesSpec(List *args, Oid *lefttype, Oid *righttype)
01037 {
01038 TypeName *typeName;
01039
01040 Assert(args != NIL);
01041
01042 typeName = (TypeName *) linitial(args);
01043 *lefttype = typenameTypeId(NULL, typeName);
01044
01045 if (list_length(args) > 1)
01046 {
01047 typeName = (TypeName *) lsecond(args);
01048 *righttype = typenameTypeId(NULL, typeName);
01049 }
01050 else
01051 *righttype = *lefttype;
01052
01053 if (list_length(args) > 2)
01054 ereport(ERROR,
01055 (errcode(ERRCODE_SYNTAX_ERROR),
01056 errmsg("one or two argument types must be specified")));
01057 }
01058
01059
01060
01061
01062
01063
01064 static void
01065 assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
01066 {
01067 Operator optup;
01068 Form_pg_operator opform;
01069
01070
01071 optup = SearchSysCache1(OPEROID, ObjectIdGetDatum(member->object));
01072 if (optup == NULL)
01073 elog(ERROR, "cache lookup failed for operator %u", member->object);
01074 opform = (Form_pg_operator) GETSTRUCT(optup);
01075
01076
01077
01078
01079 if (opform->oprkind != 'b')
01080 ereport(ERROR,
01081 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01082 errmsg("index operators must be binary")));
01083
01084 if (OidIsValid(member->sortfamily))
01085 {
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096 HeapTuple amtup;
01097 Form_pg_am pg_am;
01098
01099 amtup = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
01100 if (amtup == NULL)
01101 elog(ERROR, "cache lookup failed for access method %u", amoid);
01102 pg_am = (Form_pg_am) GETSTRUCT(amtup);
01103
01104 if (!pg_am->amcanorderbyop)
01105 ereport(ERROR,
01106 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01107 errmsg("access method \"%s\" does not support ordering operators",
01108 NameStr(pg_am->amname))));
01109
01110 ReleaseSysCache(amtup);
01111 }
01112 else
01113 {
01114
01115
01116
01117 if (opform->oprresult != BOOLOID)
01118 ereport(ERROR,
01119 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01120 errmsg("index search operators must return boolean")));
01121 }
01122
01123
01124
01125
01126 if (!OidIsValid(member->lefttype))
01127 member->lefttype = opform->oprleft;
01128 if (!OidIsValid(member->righttype))
01129 member->righttype = opform->oprright;
01130
01131 ReleaseSysCache(optup);
01132 }
01133
01134
01135
01136
01137
01138 static void
01139 assignProcTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
01140 {
01141 HeapTuple proctup;
01142 Form_pg_proc procform;
01143
01144
01145 proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(member->object));
01146 if (proctup == NULL)
01147 elog(ERROR, "cache lookup failed for function %u", member->object);
01148 procform = (Form_pg_proc) GETSTRUCT(proctup);
01149
01150
01151
01152
01153
01154
01155 if (amoid == BTREE_AM_OID)
01156 {
01157 if (member->number == BTORDER_PROC)
01158 {
01159 if (procform->pronargs != 2)
01160 ereport(ERROR,
01161 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01162 errmsg("btree comparison procedures must have two arguments")));
01163 if (procform->prorettype != INT4OID)
01164 ereport(ERROR,
01165 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01166 errmsg("btree comparison procedures must return integer")));
01167
01168
01169
01170
01171
01172 if (!OidIsValid(member->lefttype))
01173 member->lefttype = procform->proargtypes.values[0];
01174 if (!OidIsValid(member->righttype))
01175 member->righttype = procform->proargtypes.values[1];
01176 }
01177 else if (member->number == BTSORTSUPPORT_PROC)
01178 {
01179 if (procform->pronargs != 1 ||
01180 procform->proargtypes.values[0] != INTERNALOID)
01181 ereport(ERROR,
01182 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01183 errmsg("btree sort support procedures must accept type \"internal\"")));
01184 if (procform->prorettype != VOIDOID)
01185 ereport(ERROR,
01186 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01187 errmsg("btree sort support procedures must return void")));
01188
01189
01190
01191
01192 }
01193 }
01194 else if (amoid == HASH_AM_OID)
01195 {
01196 if (procform->pronargs != 1)
01197 ereport(ERROR,
01198 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01199 errmsg("hash procedures must have one argument")));
01200 if (procform->prorettype != INT4OID)
01201 ereport(ERROR,
01202 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01203 errmsg("hash procedures must return integer")));
01204
01205
01206
01207
01208 if (!OidIsValid(member->lefttype))
01209 member->lefttype = procform->proargtypes.values[0];
01210 if (!OidIsValid(member->righttype))
01211 member->righttype = procform->proargtypes.values[0];
01212 }
01213
01214
01215
01216
01217
01218
01219 if (!OidIsValid(member->lefttype))
01220 member->lefttype = typeoid;
01221 if (!OidIsValid(member->righttype))
01222 member->righttype = typeoid;
01223
01224 if (!OidIsValid(member->lefttype) || !OidIsValid(member->righttype))
01225 ereport(ERROR,
01226 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01227 errmsg("associated data types must be specified for index support procedure")));
01228
01229 ReleaseSysCache(proctup);
01230 }
01231
01232
01233
01234
01235
01236 static void
01237 addFamilyMember(List **list, OpFamilyMember *member, bool isProc)
01238 {
01239 ListCell *l;
01240
01241 foreach(l, *list)
01242 {
01243 OpFamilyMember *old = (OpFamilyMember *) lfirst(l);
01244
01245 if (old->number == member->number &&
01246 old->lefttype == member->lefttype &&
01247 old->righttype == member->righttype)
01248 {
01249 if (isProc)
01250 ereport(ERROR,
01251 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01252 errmsg("procedure number %d for (%s,%s) appears more than once",
01253 member->number,
01254 format_type_be(member->lefttype),
01255 format_type_be(member->righttype))));
01256 else
01257 ereport(ERROR,
01258 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
01259 errmsg("operator number %d for (%s,%s) appears more than once",
01260 member->number,
01261 format_type_be(member->lefttype),
01262 format_type_be(member->righttype))));
01263 }
01264 }
01265 *list = lappend(*list, member);
01266 }
01267
01268
01269
01270
01271
01272
01273
01274
01275 static void
01276 storeOperators(List *opfamilyname, Oid amoid,
01277 Oid opfamilyoid, Oid opclassoid,
01278 List *operators, bool isAdd)
01279 {
01280 Relation rel;
01281 Datum values[Natts_pg_amop];
01282 bool nulls[Natts_pg_amop];
01283 HeapTuple tup;
01284 Oid entryoid;
01285 ObjectAddress myself,
01286 referenced;
01287 ListCell *l;
01288
01289 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
01290
01291 foreach(l, operators)
01292 {
01293 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
01294 char oppurpose;
01295
01296
01297
01298
01299
01300 if (isAdd &&
01301 SearchSysCacheExists4(AMOPSTRATEGY,
01302 ObjectIdGetDatum(opfamilyoid),
01303 ObjectIdGetDatum(op->lefttype),
01304 ObjectIdGetDatum(op->righttype),
01305 Int16GetDatum(op->number)))
01306 ereport(ERROR,
01307 (errcode(ERRCODE_DUPLICATE_OBJECT),
01308 errmsg("operator %d(%s,%s) already exists in operator family \"%s\"",
01309 op->number,
01310 format_type_be(op->lefttype),
01311 format_type_be(op->righttype),
01312 NameListToString(opfamilyname))));
01313
01314 oppurpose = OidIsValid(op->sortfamily) ? AMOP_ORDER : AMOP_SEARCH;
01315
01316
01317 memset(values, 0, sizeof(values));
01318 memset(nulls, false, sizeof(nulls));
01319
01320 values[Anum_pg_amop_amopfamily - 1] = ObjectIdGetDatum(opfamilyoid);
01321 values[Anum_pg_amop_amoplefttype - 1] = ObjectIdGetDatum(op->lefttype);
01322 values[Anum_pg_amop_amoprighttype - 1] = ObjectIdGetDatum(op->righttype);
01323 values[Anum_pg_amop_amopstrategy - 1] = Int16GetDatum(op->number);
01324 values[Anum_pg_amop_amoppurpose - 1] = CharGetDatum(oppurpose);
01325 values[Anum_pg_amop_amopopr - 1] = ObjectIdGetDatum(op->object);
01326 values[Anum_pg_amop_amopmethod - 1] = ObjectIdGetDatum(amoid);
01327 values[Anum_pg_amop_amopsortfamily - 1] = ObjectIdGetDatum(op->sortfamily);
01328
01329 tup = heap_form_tuple(rel->rd_att, values, nulls);
01330
01331 entryoid = simple_heap_insert(rel, tup);
01332
01333 CatalogUpdateIndexes(rel, tup);
01334
01335 heap_freetuple(tup);
01336
01337
01338 myself.classId = AccessMethodOperatorRelationId;
01339 myself.objectId = entryoid;
01340 myself.objectSubId = 0;
01341
01342 referenced.classId = OperatorRelationId;
01343 referenced.objectId = op->object;
01344 referenced.objectSubId = 0;
01345
01346 if (OidIsValid(opclassoid))
01347 {
01348
01349 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
01350
01351
01352 referenced.classId = OperatorClassRelationId;
01353 referenced.objectId = opclassoid;
01354 referenced.objectSubId = 0;
01355 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
01356 }
01357 else
01358 {
01359
01360 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
01361
01362
01363 referenced.classId = OperatorFamilyRelationId;
01364 referenced.objectId = opfamilyoid;
01365 referenced.objectSubId = 0;
01366 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
01367 }
01368
01369
01370 if (OidIsValid(op->sortfamily))
01371 {
01372 referenced.classId = OperatorFamilyRelationId;
01373 referenced.objectId = op->sortfamily;
01374 referenced.objectSubId = 0;
01375 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
01376 }
01377
01378 InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
01379 entryoid, 0);
01380 }
01381
01382 heap_close(rel, RowExclusiveLock);
01383 }
01384
01385
01386
01387
01388
01389
01390
01391
01392 static void
01393 storeProcedures(List *opfamilyname, Oid amoid,
01394 Oid opfamilyoid, Oid opclassoid,
01395 List *procedures, bool isAdd)
01396 {
01397 Relation rel;
01398 Datum values[Natts_pg_amproc];
01399 bool nulls[Natts_pg_amproc];
01400 HeapTuple tup;
01401 Oid entryoid;
01402 ObjectAddress myself,
01403 referenced;
01404 ListCell *l;
01405
01406 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
01407
01408 foreach(l, procedures)
01409 {
01410 OpFamilyMember *proc = (OpFamilyMember *) lfirst(l);
01411
01412
01413
01414
01415
01416 if (isAdd &&
01417 SearchSysCacheExists4(AMPROCNUM,
01418 ObjectIdGetDatum(opfamilyoid),
01419 ObjectIdGetDatum(proc->lefttype),
01420 ObjectIdGetDatum(proc->righttype),
01421 Int16GetDatum(proc->number)))
01422 ereport(ERROR,
01423 (errcode(ERRCODE_DUPLICATE_OBJECT),
01424 errmsg("function %d(%s,%s) already exists in operator family \"%s\"",
01425 proc->number,
01426 format_type_be(proc->lefttype),
01427 format_type_be(proc->righttype),
01428 NameListToString(opfamilyname))));
01429
01430
01431 memset(values, 0, sizeof(values));
01432 memset(nulls, false, sizeof(nulls));
01433
01434 values[Anum_pg_amproc_amprocfamily - 1] = ObjectIdGetDatum(opfamilyoid);
01435 values[Anum_pg_amproc_amproclefttype - 1] = ObjectIdGetDatum(proc->lefttype);
01436 values[Anum_pg_amproc_amprocrighttype - 1] = ObjectIdGetDatum(proc->righttype);
01437 values[Anum_pg_amproc_amprocnum - 1] = Int16GetDatum(proc->number);
01438 values[Anum_pg_amproc_amproc - 1] = ObjectIdGetDatum(proc->object);
01439
01440 tup = heap_form_tuple(rel->rd_att, values, nulls);
01441
01442 entryoid = simple_heap_insert(rel, tup);
01443
01444 CatalogUpdateIndexes(rel, tup);
01445
01446 heap_freetuple(tup);
01447
01448
01449 myself.classId = AccessMethodProcedureRelationId;
01450 myself.objectId = entryoid;
01451 myself.objectSubId = 0;
01452
01453 referenced.classId = ProcedureRelationId;
01454 referenced.objectId = proc->object;
01455 referenced.objectSubId = 0;
01456
01457 if (OidIsValid(opclassoid))
01458 {
01459
01460 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
01461
01462
01463 referenced.classId = OperatorClassRelationId;
01464 referenced.objectId = opclassoid;
01465 referenced.objectSubId = 0;
01466 recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
01467 }
01468 else
01469 {
01470
01471 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
01472
01473
01474 referenced.classId = OperatorFamilyRelationId;
01475 referenced.objectId = opfamilyoid;
01476 referenced.objectSubId = 0;
01477 recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
01478 }
01479
01480 InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
01481 entryoid, 0);
01482 }
01483
01484 heap_close(rel, RowExclusiveLock);
01485 }
01486
01487
01488
01489
01490
01491
01492
01493
01494 static void
01495 dropOperators(List *opfamilyname, Oid amoid, Oid opfamilyoid,
01496 List *operators)
01497 {
01498 ListCell *l;
01499
01500 foreach(l, operators)
01501 {
01502 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
01503 Oid amopid;
01504 ObjectAddress object;
01505
01506 amopid = GetSysCacheOid4(AMOPSTRATEGY,
01507 ObjectIdGetDatum(opfamilyoid),
01508 ObjectIdGetDatum(op->lefttype),
01509 ObjectIdGetDatum(op->righttype),
01510 Int16GetDatum(op->number));
01511 if (!OidIsValid(amopid))
01512 ereport(ERROR,
01513 (errcode(ERRCODE_UNDEFINED_OBJECT),
01514 errmsg("operator %d(%s,%s) does not exist in operator family \"%s\"",
01515 op->number,
01516 format_type_be(op->lefttype),
01517 format_type_be(op->righttype),
01518 NameListToString(opfamilyname))));
01519
01520 object.classId = AccessMethodOperatorRelationId;
01521 object.objectId = amopid;
01522 object.objectSubId = 0;
01523
01524 performDeletion(&object, DROP_RESTRICT, 0);
01525 }
01526 }
01527
01528
01529
01530
01531
01532
01533
01534 static void
01535 dropProcedures(List *opfamilyname, Oid amoid, Oid opfamilyoid,
01536 List *procedures)
01537 {
01538 ListCell *l;
01539
01540 foreach(l, procedures)
01541 {
01542 OpFamilyMember *op = (OpFamilyMember *) lfirst(l);
01543 Oid amprocid;
01544 ObjectAddress object;
01545
01546 amprocid = GetSysCacheOid4(AMPROCNUM,
01547 ObjectIdGetDatum(opfamilyoid),
01548 ObjectIdGetDatum(op->lefttype),
01549 ObjectIdGetDatum(op->righttype),
01550 Int16GetDatum(op->number));
01551 if (!OidIsValid(amprocid))
01552 ereport(ERROR,
01553 (errcode(ERRCODE_UNDEFINED_OBJECT),
01554 errmsg("function %d(%s,%s) does not exist in operator family \"%s\"",
01555 op->number,
01556 format_type_be(op->lefttype),
01557 format_type_be(op->righttype),
01558 NameListToString(opfamilyname))));
01559
01560 object.classId = AccessMethodProcedureRelationId;
01561 object.objectId = amprocid;
01562 object.objectSubId = 0;
01563
01564 performDeletion(&object, DROP_RESTRICT, 0);
01565 }
01566 }
01567
01568
01569
01570
01571 void
01572 RemoveOpFamilyById(Oid opfamilyOid)
01573 {
01574 Relation rel;
01575 HeapTuple tup;
01576
01577 rel = heap_open(OperatorFamilyRelationId, RowExclusiveLock);
01578
01579 tup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyOid));
01580 if (!HeapTupleIsValid(tup))
01581 elog(ERROR, "cache lookup failed for opfamily %u", opfamilyOid);
01582
01583 simple_heap_delete(rel, &tup->t_self);
01584
01585 ReleaseSysCache(tup);
01586
01587 heap_close(rel, RowExclusiveLock);
01588 }
01589
01590 void
01591 RemoveOpClassById(Oid opclassOid)
01592 {
01593 Relation rel;
01594 HeapTuple tup;
01595
01596 rel = heap_open(OperatorClassRelationId, RowExclusiveLock);
01597
01598 tup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassOid));
01599 if (!HeapTupleIsValid(tup))
01600 elog(ERROR, "cache lookup failed for opclass %u", opclassOid);
01601
01602 simple_heap_delete(rel, &tup->t_self);
01603
01604 ReleaseSysCache(tup);
01605
01606 heap_close(rel, RowExclusiveLock);
01607 }
01608
01609 void
01610 RemoveAmOpEntryById(Oid entryOid)
01611 {
01612 Relation rel;
01613 HeapTuple tup;
01614 ScanKeyData skey[1];
01615 SysScanDesc scan;
01616
01617 ScanKeyInit(&skey[0],
01618 ObjectIdAttributeNumber,
01619 BTEqualStrategyNumber, F_OIDEQ,
01620 ObjectIdGetDatum(entryOid));
01621
01622 rel = heap_open(AccessMethodOperatorRelationId, RowExclusiveLock);
01623
01624 scan = systable_beginscan(rel, AccessMethodOperatorOidIndexId, true,
01625 SnapshotNow, 1, skey);
01626
01627
01628 tup = systable_getnext(scan);
01629 if (!HeapTupleIsValid(tup))
01630 elog(ERROR, "could not find tuple for amop entry %u", entryOid);
01631
01632 simple_heap_delete(rel, &tup->t_self);
01633
01634 systable_endscan(scan);
01635 heap_close(rel, RowExclusiveLock);
01636 }
01637
01638 void
01639 RemoveAmProcEntryById(Oid entryOid)
01640 {
01641 Relation rel;
01642 HeapTuple tup;
01643 ScanKeyData skey[1];
01644 SysScanDesc scan;
01645
01646 ScanKeyInit(&skey[0],
01647 ObjectIdAttributeNumber,
01648 BTEqualStrategyNumber, F_OIDEQ,
01649 ObjectIdGetDatum(entryOid));
01650
01651 rel = heap_open(AccessMethodProcedureRelationId, RowExclusiveLock);
01652
01653 scan = systable_beginscan(rel, AccessMethodProcedureOidIndexId, true,
01654 SnapshotNow, 1, skey);
01655
01656
01657 tup = systable_getnext(scan);
01658 if (!HeapTupleIsValid(tup))
01659 elog(ERROR, "could not find tuple for amproc entry %u", entryOid);
01660
01661 simple_heap_delete(rel, &tup->t_self);
01662
01663 systable_endscan(scan);
01664 heap_close(rel, RowExclusiveLock);
01665 }
01666
01667 static char *
01668 get_am_name(Oid amOid)
01669 {
01670 HeapTuple tup;
01671 char *result = NULL;
01672
01673 tup = SearchSysCache1(AMOID, ObjectIdGetDatum(amOid));
01674 if (HeapTupleIsValid(tup))
01675 {
01676 result = pstrdup(NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
01677 ReleaseSysCache(tup);
01678 }
01679 return result;
01680 }
01681
01682
01683
01684
01685
01686
01687
01688 void
01689 IsThereOpClassInNamespace(const char *opcname, Oid opcmethod,
01690 Oid opcnamespace)
01691 {
01692
01693 if (SearchSysCacheExists3(CLAAMNAMENSP,
01694 ObjectIdGetDatum(opcmethod),
01695 CStringGetDatum(opcname),
01696 ObjectIdGetDatum(opcnamespace)))
01697 ereport(ERROR,
01698 (errcode(ERRCODE_DUPLICATE_OBJECT),
01699 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
01700 opcname,
01701 get_am_name(opcmethod),
01702 get_namespace_name(opcnamespace))));
01703 }
01704
01705
01706
01707
01708
01709
01710
01711 void
01712 IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod,
01713 Oid opfnamespace)
01714 {
01715
01716 if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
01717 ObjectIdGetDatum(opfmethod),
01718 CStringGetDatum(opfname),
01719 ObjectIdGetDatum(opfnamespace)))
01720 ereport(ERROR,
01721 (errcode(ERRCODE_DUPLICATE_OBJECT),
01722 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
01723 opfname,
01724 get_am_name(opfmethod),
01725 get_namespace_name(opfnamespace))));
01726 }
01727
01728
01729
01730
01731
01732
01733
01734 Oid
01735 get_am_oid(const char *amname, bool missing_ok)
01736 {
01737 Oid oid;
01738
01739 oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
01740 if (!OidIsValid(oid) && !missing_ok)
01741 ereport(ERROR,
01742 (errcode(ERRCODE_UNDEFINED_OBJECT),
01743 errmsg("access method \"%s\" does not exist", amname)));
01744 return oid;
01745 }