Index: cluster.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/cluster.c,v retrieving revision 1.82 diff -c -u -r1.82 cluster.c --- cluster.c 2002/06/20 20:29:26 1.82 +++ cluster.c 2002/07/05 06:25:17 @@ -26,44 +26,62 @@ #include "access/heapam.h" #include "catalog/heap.h" #include "catalog/index.h" +#include "catalog/catname.h" #include "catalog/pg_index.h" #include "catalog/pg_proc.h" #include "commands/cluster.h" #include "commands/tablecmds.h" #include "miscadmin.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" static Oid copy_heap(Oid OIDOldHeap, const char *NewName); -static Oid copy_index(Oid OIDOldIndex, Oid OIDNewHeap, - const char *NewIndexName); static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); /* + * We need one of these structs for each index in the relation to be + * clustered. It's basically the data needed by index_create() so + * we can recreate the indexes after destroying the old heap. + */ +typedef struct +{ + char *indexName; + IndexInfo *indexInfo; + Oid accessMethodOID; + Oid *classOID; + Oid indexOID; + bool isPrimary; +} IndexAttrs; + +/* * cluster * * STILL TO DO: - * Create a list of all the other indexes on this relation. Because - * the cluster will wreck all the tids, I'll need to destroy bogus - * indexes. The user will have to re-create them. Not nice, but - * I'm not a nice guy. The alternative is to try some kind of post - * destroy re-build. This may be possible. I'll check out what the - * index create functiond want in the way of paramaters. On the other - * hand, re-creating n indexes may blow out the space. + * Keep foreign keys, permissions and inheritance of the clustered table. + * + * We need to look at making use of the ability to write a new version of a + * table (or index) under a new relfilenode value, without changing the + * table's OID. */ void cluster(RangeVar *oldrelation, char *oldindexname) { Oid OIDOldHeap, OIDOldIndex, - OIDNewHeap, - OIDNewIndex; + OIDNewHeap; Relation OldHeap, - OldIndex; + OldIndex, + indexRelation; char NewHeapName[NAMEDATALEN]; - char NewIndexName[NAMEDATALEN]; + HeapTuple indexTuple; + ScanKeyData entry; + HeapScanDesc scan; + List *indexes=NIL; + List *elem; + IndexAttrs *attrs; /* * We grab exclusive access to the target rel and index for the @@ -95,6 +113,53 @@ index_close(OldIndex); /* + * Save the information of all indexes on the relation. + * Get the info from IndexRelationName. + */ + indexRelation = heap_openr(IndexRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, + F_OIDEQ, ObjectIdGetDatum(OIDOldHeap)); + scan = heap_beginscan(indexRelation, SnapshotNow, 1, &entry); + while ((indexTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple); + HeapTuple tuple; + Form_pg_class class; + + attrs = (IndexAttrs *) palloc(sizeof(IndexAttrs)); + attrs->indexInfo = BuildIndexInfo(index); + attrs->isPrimary = index->indisprimary; + attrs->indexOID = index->indexrelid; + + /* The opclasses are copied verbatim from the original indexes. + */ + attrs->classOID = (Oid *)palloc(sizeof(Oid) * + attrs->indexInfo->ii_NumIndexAttrs); + memcpy(attrs->classOID, index->indclass, + sizeof(Oid) * attrs->indexInfo->ii_NumIndexAttrs); + + /* Name and access method of each index come from + * RelationRelationName. + */ + tuple = SearchSysCache(RELOID, ObjectIdGetDatum(attrs->indexOID), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "CLUSTER: cannot find index %u for table %s", + attrs->indexOID, oldrelation->relname); + class = (Form_pg_class) GETSTRUCT(tuple); + attrs->indexName = pstrdup(NameStr(class->relname)); + attrs->accessMethodOID = class->relam; + ReleaseSysCache(tuple); + + /* Cons the data to the index list. We don't care about ordering, + * and this is more efficient. + */ + indexes=lcons((void *)attrs, indexes); + } + heap_endscan(scan); + heap_close(indexRelation, AccessShareLock); + + /* * Create the new heap with a temporary name. */ snprintf(NewHeapName, NAMEDATALEN, "temp_%u", OIDOldHeap); @@ -111,13 +176,6 @@ /* To make the new heap's data visible. */ CommandCounterIncrement(); - /* Create new index over the tuples of the new heap. */ - snprintf(NewIndexName, NAMEDATALEN, "temp_%u", OIDOldIndex); - - OIDNewIndex = copy_index(OIDOldIndex, OIDNewHeap, NewIndexName); - - CommandCounterIncrement(); - /* Destroy old heap (along with its index) and rename new. */ heap_drop_with_catalog(OIDOldHeap, allowSystemTableMods); @@ -128,9 +186,21 @@ /* This one might be unnecessary, but let's be safe. */ CommandCounterIncrement(); - renamerel(OIDNewIndex, oldindexname); + /* Recreate the indexes on the relation. + */ + foreach (elem, indexes) + { + attrs=(IndexAttrs *) lfirst(elem); + index_create(OIDNewHeap, attrs->indexName, attrs->indexInfo, + attrs->accessMethodOID, attrs->classOID, attrs->isPrimary, + allowSystemTableMods); + setRelhasindex(OIDNewHeap, true, attrs->isPrimary, InvalidOid); + CommandCounterIncrement(); + } } +/* Create and initialize the new heap + */ static Oid copy_heap(Oid OIDOldHeap, const char *NewName) { @@ -174,42 +244,8 @@ return OIDNewHeap; } -static Oid -copy_index(Oid OIDOldIndex, Oid OIDNewHeap, const char *NewIndexName) -{ - Oid OIDNewIndex; - Relation OldIndex, - NewHeap; - IndexInfo *indexInfo; - - NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock); - OldIndex = index_open(OIDOldIndex); - - /* - * Create a new index like the old one. To do this I get the info - * from pg_index, and add a new index with a temporary name (that will - * be changed later). - */ - indexInfo = BuildIndexInfo(OldIndex->rd_index); - - OIDNewIndex = index_create(OIDNewHeap, - NewIndexName, - indexInfo, - OldIndex->rd_rel->relam, - OldIndex->rd_index->indclass, - OldIndex->rd_index->indisprimary, - allowSystemTableMods); - - setRelhasindex(OIDNewHeap, true, - OldIndex->rd_index->indisprimary, InvalidOid); - - index_close(OldIndex); - heap_close(NewHeap, NoLock); - - return OIDNewIndex; -} - - +/* Load the data into the new heap, clustered. + */ static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex) {