11
11
*
12
12
*
13
13
* IDENTIFICATION
14
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.121 2004/05/05 04:48:45 tgl Exp $
14
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.122 2004/05/06 16:10:57 tgl Exp $
15
15
*
16
16
*-------------------------------------------------------------------------
17
17
*/
31
31
#include "miscadmin.h"
32
32
#include "utils/acl.h"
33
33
#include "utils/fmgroids.h"
34
+ #include "utils/inval.h"
34
35
#include "utils/lsyscache.h"
35
36
#include "utils/syscache.h"
36
37
#include "utils/relcache.h"
@@ -48,7 +49,6 @@ typedef struct
48
49
IndexInfo * indexInfo ;
49
50
Oid accessMethodOID ;
50
51
Oid * classOID ;
51
- bool isclustered ;
52
52
} IndexAttrs ;
53
53
54
54
/*
@@ -246,8 +246,7 @@ cluster(ClusterStmt *stmt)
246
246
static void
247
247
cluster_rel (RelToCluster * rvtc , bool recheck )
248
248
{
249
- Relation OldHeap ,
250
- OldIndex ;
249
+ Relation OldHeap ;
251
250
252
251
/* Check for user-requested abort. */
253
252
CHECK_FOR_INTERRUPTS ();
@@ -300,18 +299,41 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
300
299
/*
301
300
* We grab exclusive access to the target rel and index for the
302
301
* duration of the transaction. (This is redundant for the single-
303
- * transaction case, since cluster() already did it.)
302
+ * transaction case, since cluster() already did it.) The index
303
+ * lock is taken inside check_index_is_clusterable.
304
304
*/
305
305
OldHeap = heap_open (rvtc -> tableOid , AccessExclusiveLock );
306
306
307
- OldIndex = index_open (rvtc -> indexOid );
307
+ /* Check index is valid to cluster on */
308
+ check_index_is_clusterable (OldHeap , rvtc -> indexOid );
309
+
310
+ /* rebuild_relation does all the dirty work */
311
+ rebuild_relation (OldHeap , rvtc -> indexOid );
312
+
313
+ /* NB: rebuild_relation does heap_close() on OldHeap */
314
+ }
315
+
316
+ /*
317
+ * Verify that the specified index is a legitimate index to cluster on
318
+ *
319
+ * Side effect: obtains exclusive lock on the index. The caller should
320
+ * already have exclusive lock on the table, so the index lock is likely
321
+ * redundant, but it seems best to grab it anyway to ensure the index
322
+ * definition can't change under us.
323
+ */
324
+ void
325
+ check_index_is_clusterable (Relation OldHeap , Oid indexOid )
326
+ {
327
+ Relation OldIndex ;
328
+
329
+ OldIndex = index_open (indexOid );
308
330
LockRelation (OldIndex , AccessExclusiveLock );
309
331
310
332
/*
311
333
* Check that index is in fact an index on the given relation
312
334
*/
313
335
if (OldIndex -> rd_index == NULL ||
314
- OldIndex -> rd_index -> indrelid != rvtc -> tableOid )
336
+ OldIndex -> rd_index -> indrelid != RelationGetRelid ( OldHeap ) )
315
337
ereport (ERROR ,
316
338
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
317
339
errmsg ("\"%s\" is not an index for table \"%s\"" ,
@@ -386,11 +408,6 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
386
408
387
409
/* Drop relcache refcnt on OldIndex, but keep lock */
388
410
index_close (OldIndex );
389
-
390
- /* rebuild_relation does all the dirty work */
391
- rebuild_relation (OldHeap , rvtc -> indexOid );
392
-
393
- /* NB: rebuild_relation does heap_close() on OldHeap */
394
411
}
395
412
396
413
/*
@@ -410,13 +427,14 @@ void
410
427
rebuild_relation (Relation OldHeap , Oid indexOid )
411
428
{
412
429
Oid tableOid = RelationGetRelid (OldHeap );
430
+ Oid oldClusterIndex ;
413
431
List * indexes ;
414
432
Oid OIDNewHeap ;
415
433
char NewHeapName [NAMEDATALEN ];
416
434
ObjectAddress object ;
417
435
418
436
/* Save the information about all indexes on the relation. */
419
- indexes = get_indexattr_list (OldHeap , indexOid );
437
+ indexes = get_indexattr_list (OldHeap , & oldClusterIndex );
420
438
421
439
/* Close relcache entry, but keep lock until transaction commit */
422
440
heap_close (OldHeap , NoLock );
@@ -469,7 +487,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
469
487
* Recreate each index on the relation. We do not need
470
488
* CommandCounterIncrement() because rebuild_indexes does it.
471
489
*/
472
- rebuild_indexes (tableOid , indexes );
490
+ rebuild_indexes (tableOid , indexes ,
491
+ (OidIsValid (indexOid ) ? indexOid : oldClusterIndex ));
473
492
}
474
493
475
494
/*
@@ -572,14 +591,18 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
572
591
573
592
/*
574
593
* Get the necessary info about the indexes of the relation and
575
- * return a list of IndexAttrs structures.
594
+ * return a list of IndexAttrs structures. Also, *OldClusterIndex
595
+ * is set to the OID of the existing clustered index, or InvalidOid
596
+ * if there is none.
576
597
*/
577
598
List *
578
- get_indexattr_list (Relation OldHeap , Oid OldIndex )
599
+ get_indexattr_list (Relation OldHeap , Oid * OldClusterIndex )
579
600
{
580
601
List * indexes = NIL ;
581
602
List * indlist ;
582
603
604
+ * OldClusterIndex = InvalidOid ;
605
+
583
606
/* Ask the relcache to produce a list of the indexes of the old rel */
584
607
foreach (indlist , RelationGetIndexList (OldHeap ))
585
608
{
@@ -598,16 +621,12 @@ get_indexattr_list(Relation OldHeap, Oid OldIndex)
598
621
palloc (sizeof (Oid ) * attrs -> indexInfo -> ii_NumIndexAttrs );
599
622
memcpy (attrs -> classOID , oldIndex -> rd_index -> indclass ,
600
623
sizeof (Oid ) * attrs -> indexInfo -> ii_NumIndexAttrs );
601
- /* We adjust the isclustered attribute to correct new state */
602
- attrs -> isclustered = ( indexOID == OldIndex ) ;
624
+ if ( oldIndex -> rd_index -> indisclustered )
625
+ * OldClusterIndex = indexOID ;
603
626
604
627
index_close (oldIndex );
605
628
606
- /*
607
- * Cons the gathered data into the list. We do not care about
608
- * ordering, and this is more efficient than append.
609
- */
610
- indexes = lcons (attrs , indexes );
629
+ indexes = lappend (indexes , attrs );
611
630
}
612
631
613
632
return indexes ;
@@ -616,25 +635,30 @@ get_indexattr_list(Relation OldHeap, Oid OldIndex)
616
635
/*
617
636
* Create new indexes and swap the filenodes with old indexes. Then drop
618
637
* the new index (carrying the old index filenode along).
638
+ *
639
+ * OIDClusterIndex is the OID of the index to be marked as clustered, or
640
+ * InvalidOid if none should be marked clustered.
619
641
*/
620
642
void
621
- rebuild_indexes (Oid OIDOldHeap , List * indexes )
643
+ rebuild_indexes (Oid OIDOldHeap , List * indexes , Oid OIDClusterIndex )
622
644
{
623
645
List * elem ;
624
646
625
647
foreach (elem , indexes )
626
648
{
627
649
IndexAttrs * attrs = (IndexAttrs * ) lfirst (elem );
650
+ Oid oldIndexOID = attrs -> indexOID ;
628
651
Oid newIndexOID ;
629
652
char newIndexName [NAMEDATALEN ];
653
+ bool isclustered ;
630
654
ObjectAddress object ;
631
655
Form_pg_index index ;
632
656
HeapTuple tuple ;
633
657
Relation pg_index ;
634
658
635
659
/* Create the new index under a temporary name */
636
660
snprintf (newIndexName , sizeof (newIndexName ),
637
- "pg_temp_%u" , attrs -> indexOID );
661
+ "pg_temp_%u" , oldIndexOID );
638
662
639
663
/*
640
664
* The new index will have primary and constraint status set to
@@ -654,26 +678,30 @@ rebuild_indexes(Oid OIDOldHeap, List *indexes)
654
678
CommandCounterIncrement ();
655
679
656
680
/* Swap the filenodes. */
657
- swap_relfilenodes (attrs -> indexOID , newIndexOID );
681
+ swap_relfilenodes (oldIndexOID , newIndexOID );
658
682
659
683
CommandCounterIncrement ();
660
684
661
685
/*
662
686
* Make sure that indisclustered is correct: it should be set only
663
- * for the index we just clustered on .
687
+ * for the index specified by the caller .
664
688
*/
689
+ isclustered = (oldIndexOID == OIDClusterIndex );
690
+
665
691
pg_index = heap_openr (IndexRelationName , RowExclusiveLock );
666
692
tuple = SearchSysCacheCopy (INDEXRELID ,
667
- ObjectIdGetDatum (attrs -> indexOID ),
693
+ ObjectIdGetDatum (oldIndexOID ),
668
694
0 , 0 , 0 );
669
695
if (!HeapTupleIsValid (tuple ))
670
- elog (ERROR , "cache lookup failed for index %u" , attrs -> indexOID );
696
+ elog (ERROR , "cache lookup failed for index %u" , oldIndexOID );
671
697
index = (Form_pg_index ) GETSTRUCT (tuple );
672
- if (index -> indisclustered != attrs -> isclustered )
698
+ if (index -> indisclustered != isclustered )
673
699
{
674
- index -> indisclustered = attrs -> isclustered ;
700
+ index -> indisclustered = isclustered ;
675
701
simple_heap_update (pg_index , & tuple -> t_self , tuple );
676
702
CatalogUpdateIndexes (pg_index , tuple );
703
+ /* Ensure we see the update in the index's relcache entry */
704
+ CacheInvalidateRelcacheByRelid (oldIndexOID );
677
705
}
678
706
heap_freetuple (tuple );
679
707
heap_close (pg_index , RowExclusiveLock );
0 commit comments