Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8325a8d

Browse files
committed
Make ALTER COLUMN TYPE preserve clustered status for indexes it doesn't
modify. Also fix a passel of problems with ALTER TABLE CLUSTER ON: failure to check that the index is safe to cluster on (or even belongs to the indicated rel, or even exists), and failure to broadcast a relcache flush event when changing an index's state.
1 parent eee6f9d commit 8325a8d

File tree

5 files changed

+100
-39
lines changed

5 files changed

+100
-39
lines changed

src/backend/commands/cluster.c

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* 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 $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -31,6 +31,7 @@
3131
#include "miscadmin.h"
3232
#include "utils/acl.h"
3333
#include "utils/fmgroids.h"
34+
#include "utils/inval.h"
3435
#include "utils/lsyscache.h"
3536
#include "utils/syscache.h"
3637
#include "utils/relcache.h"
@@ -48,7 +49,6 @@ typedef struct
4849
IndexInfo *indexInfo;
4950
Oid accessMethodOID;
5051
Oid *classOID;
51-
bool isclustered;
5252
} IndexAttrs;
5353

5454
/*
@@ -246,8 +246,7 @@ cluster(ClusterStmt *stmt)
246246
static void
247247
cluster_rel(RelToCluster *rvtc, bool recheck)
248248
{
249-
Relation OldHeap,
250-
OldIndex;
249+
Relation OldHeap;
251250

252251
/* Check for user-requested abort. */
253252
CHECK_FOR_INTERRUPTS();
@@ -300,18 +299,41 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
300299
/*
301300
* We grab exclusive access to the target rel and index for the
302301
* 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.
304304
*/
305305
OldHeap = heap_open(rvtc->tableOid, AccessExclusiveLock);
306306

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);
308330
LockRelation(OldIndex, AccessExclusiveLock);
309331

310332
/*
311333
* Check that index is in fact an index on the given relation
312334
*/
313335
if (OldIndex->rd_index == NULL ||
314-
OldIndex->rd_index->indrelid != rvtc->tableOid)
336+
OldIndex->rd_index->indrelid != RelationGetRelid(OldHeap))
315337
ereport(ERROR,
316338
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
317339
errmsg("\"%s\" is not an index for table \"%s\"",
@@ -386,11 +408,6 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
386408

387409
/* Drop relcache refcnt on OldIndex, but keep lock */
388410
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 */
394411
}
395412

396413
/*
@@ -410,13 +427,14 @@ void
410427
rebuild_relation(Relation OldHeap, Oid indexOid)
411428
{
412429
Oid tableOid = RelationGetRelid(OldHeap);
430+
Oid oldClusterIndex;
413431
List *indexes;
414432
Oid OIDNewHeap;
415433
char NewHeapName[NAMEDATALEN];
416434
ObjectAddress object;
417435

418436
/* Save the information about all indexes on the relation. */
419-
indexes = get_indexattr_list(OldHeap, indexOid);
437+
indexes = get_indexattr_list(OldHeap, &oldClusterIndex);
420438

421439
/* Close relcache entry, but keep lock until transaction commit */
422440
heap_close(OldHeap, NoLock);
@@ -469,7 +487,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
469487
* Recreate each index on the relation. We do not need
470488
* CommandCounterIncrement() because rebuild_indexes does it.
471489
*/
472-
rebuild_indexes(tableOid, indexes);
490+
rebuild_indexes(tableOid, indexes,
491+
(OidIsValid(indexOid) ? indexOid : oldClusterIndex));
473492
}
474493

475494
/*
@@ -572,14 +591,18 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
572591

573592
/*
574593
* 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.
576597
*/
577598
List *
578-
get_indexattr_list(Relation OldHeap, Oid OldIndex)
599+
get_indexattr_list(Relation OldHeap, Oid *OldClusterIndex)
579600
{
580601
List *indexes = NIL;
581602
List *indlist;
582603

604+
*OldClusterIndex = InvalidOid;
605+
583606
/* Ask the relcache to produce a list of the indexes of the old rel */
584607
foreach(indlist, RelationGetIndexList(OldHeap))
585608
{
@@ -598,16 +621,12 @@ get_indexattr_list(Relation OldHeap, Oid OldIndex)
598621
palloc(sizeof(Oid) * attrs->indexInfo->ii_NumIndexAttrs);
599622
memcpy(attrs->classOID, oldIndex->rd_index->indclass,
600623
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;
603626

604627
index_close(oldIndex);
605628

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);
611630
}
612631

613632
return indexes;
@@ -616,25 +635,30 @@ get_indexattr_list(Relation OldHeap, Oid OldIndex)
616635
/*
617636
* Create new indexes and swap the filenodes with old indexes. Then drop
618637
* 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.
619641
*/
620642
void
621-
rebuild_indexes(Oid OIDOldHeap, List *indexes)
643+
rebuild_indexes(Oid OIDOldHeap, List *indexes, Oid OIDClusterIndex)
622644
{
623645
List *elem;
624646

625647
foreach(elem, indexes)
626648
{
627649
IndexAttrs *attrs = (IndexAttrs *) lfirst(elem);
650+
Oid oldIndexOID = attrs->indexOID;
628651
Oid newIndexOID;
629652
char newIndexName[NAMEDATALEN];
653+
bool isclustered;
630654
ObjectAddress object;
631655
Form_pg_index index;
632656
HeapTuple tuple;
633657
Relation pg_index;
634658

635659
/* Create the new index under a temporary name */
636660
snprintf(newIndexName, sizeof(newIndexName),
637-
"pg_temp_%u", attrs->indexOID);
661+
"pg_temp_%u", oldIndexOID);
638662

639663
/*
640664
* The new index will have primary and constraint status set to
@@ -654,26 +678,30 @@ rebuild_indexes(Oid OIDOldHeap, List *indexes)
654678
CommandCounterIncrement();
655679

656680
/* Swap the filenodes. */
657-
swap_relfilenodes(attrs->indexOID, newIndexOID);
681+
swap_relfilenodes(oldIndexOID, newIndexOID);
658682

659683
CommandCounterIncrement();
660684

661685
/*
662686
* 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.
664688
*/
689+
isclustered = (oldIndexOID == OIDClusterIndex);
690+
665691
pg_index = heap_openr(IndexRelationName, RowExclusiveLock);
666692
tuple = SearchSysCacheCopy(INDEXRELID,
667-
ObjectIdGetDatum(attrs->indexOID),
693+
ObjectIdGetDatum(oldIndexOID),
668694
0, 0, 0);
669695
if (!HeapTupleIsValid(tuple))
670-
elog(ERROR, "cache lookup failed for index %u", attrs->indexOID);
696+
elog(ERROR, "cache lookup failed for index %u", oldIndexOID);
671697
index = (Form_pg_index) GETSTRUCT(tuple);
672-
if (index->indisclustered != attrs->isclustered)
698+
if (index->indisclustered != isclustered)
673699
{
674-
index->indisclustered = attrs->isclustered;
700+
index->indisclustered = isclustered;
675701
simple_heap_update(pg_index, &tuple->t_self, tuple);
676702
CatalogUpdateIndexes(pg_index, tuple);
703+
/* Ensure we see the update in the index's relcache entry */
704+
CacheInvalidateRelcacheByRelid(oldIndexOID);
677705
}
678706
heap_freetuple(tuple);
679707
heap_close(pg_index, RowExclusiveLock);

src/backend/commands/tablecmds.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.103 2004/05/05 04:48:45 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.104 2004/05/06 16:10:57 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -2099,12 +2099,13 @@ ATRewriteTables(List **wqueue)
20992099
Oid OIDNewHeap;
21002100
char NewHeapName[NAMEDATALEN];
21012101
List *indexes;
2102+
Oid oldClusterIndex;
21022103
Relation OldHeap;
21032104
ObjectAddress object;
21042105

21052106
/* Save the information about all indexes on the relation. */
21062107
OldHeap = heap_open(tab->relid, NoLock);
2107-
indexes = get_indexattr_list(OldHeap, InvalidOid);
2108+
indexes = get_indexattr_list(OldHeap, &oldClusterIndex);
21082109
heap_close(OldHeap, NoLock);
21092110

21102111
/*
@@ -2148,7 +2149,7 @@ ATRewriteTables(List **wqueue)
21482149
* Rebuild each index on the relation. We do not need
21492150
* CommandCounterIncrement() because rebuild_indexes does it.
21502151
*/
2151-
rebuild_indexes(tab->relid, indexes);
2152+
rebuild_indexes(tab->relid, indexes, oldClusterIndex);
21522153
}
21532154
else
21542155
{
@@ -5004,6 +5005,9 @@ ATExecClusterOn(Relation rel, const char *indexName)
50045005
errmsg("index \"%s\" for table \"%s\" does not exist",
50055006
indexName, RelationGetRelationName(rel))));
50065007

5008+
/* Check index is valid to cluster on */
5009+
check_index_is_clusterable(rel, indexOid);
5010+
50075011
indexTuple = SearchSysCache(INDEXRELID,
50085012
ObjectIdGetDatum(indexOid),
50095013
0, 0, 0);
@@ -5050,12 +5054,16 @@ ATExecClusterOn(Relation rel, const char *indexName)
50505054
idxForm->indisclustered = false;
50515055
simple_heap_update(pg_index, &idxtuple->t_self, idxtuple);
50525056
CatalogUpdateIndexes(pg_index, idxtuple);
5057+
/* Ensure we see the update in the index's relcache entry */
5058+
CacheInvalidateRelcacheByRelid(indexOid);
50535059
}
50545060
else if (idxForm->indexrelid == indexForm->indexrelid)
50555061
{
50565062
idxForm->indisclustered = true;
50575063
simple_heap_update(pg_index, &idxtuple->t_self, idxtuple);
50585064
CatalogUpdateIndexes(pg_index, idxtuple);
5065+
/* Ensure we see the update in the index's relcache entry */
5066+
CacheInvalidateRelcacheByRelid(indexOid);
50595067
}
50605068
heap_freetuple(idxtuple);
50615069
}

src/backend/utils/cache/inval.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
* Portions Copyright (c) 1994, Regents of the University of California
7575
*
7676
* IDENTIFICATION
77-
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.60 2004/02/10 01:55:26 tgl Exp $
77+
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.61 2004/05/06 16:10:57 tgl Exp $
7878
*
7979
*-------------------------------------------------------------------------
8080
*/
@@ -88,6 +88,7 @@
8888
#include "utils/inval.h"
8989
#include "utils/memutils.h"
9090
#include "utils/relcache.h"
91+
#include "utils/syscache.h"
9192

9293

9394
/*
@@ -765,6 +766,26 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
765766
RegisterRelcacheInvalidation(databaseId, relationId, rnode);
766767
}
767768

769+
/*
770+
* CacheInvalidateRelcacheByRelid
771+
* As above, but relation is identified by passing its OID.
772+
* This is the least efficient of the three options; use one of
773+
* the above routines if you have a Relation or pg_class tuple.
774+
*/
775+
void
776+
CacheInvalidateRelcacheByRelid(Oid relid)
777+
{
778+
HeapTuple tup;
779+
780+
tup = SearchSysCache(RELOID,
781+
ObjectIdGetDatum(relid),
782+
0, 0, 0);
783+
if (!HeapTupleIsValid(tup))
784+
elog(ERROR, "cache lookup failed for relation %u", relid);
785+
CacheInvalidateRelcacheByTuple(tup);
786+
ReleaseSysCache(tup);
787+
}
788+
768789
/*
769790
* CacheRegisterSyscacheCallback
770791
* Register the specified function to be called for all future

src/include/commands/cluster.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994-5, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.21 2004/05/05 04:48:47 tgl Exp $
9+
* $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.22 2004/05/06 16:10:57 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -19,10 +19,12 @@
1919

2020
extern void cluster(ClusterStmt *stmt);
2121

22+
extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid);
2223
extern void rebuild_relation(Relation OldHeap, Oid indexOid);
2324
extern Oid make_new_heap(Oid OIDOldHeap, const char *NewName);
24-
extern List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
25-
extern void rebuild_indexes(Oid OIDOldHeap, List *indexes);
25+
extern List *get_indexattr_list(Relation OldHeap, Oid *OldClusterIndex);
26+
extern void rebuild_indexes(Oid OIDOldHeap, List *indexes,
27+
Oid OIDClusterIndex);
2628
extern void swap_relfilenodes(Oid r1, Oid r2);
2729

2830
#endif /* CLUSTER_H */

src/include/utils/inval.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/inval.h,v 1.30 2004/02/10 01:55:26 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/inval.h,v 1.31 2004/05/06 16:10:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -32,6 +32,8 @@ extern void CacheInvalidateRelcache(Relation relation);
3232

3333
extern void CacheInvalidateRelcacheByTuple(HeapTuple classTuple);
3434

35+
extern void CacheInvalidateRelcacheByRelid(Oid relid);
36+
3537
extern void CacheRegisterSyscacheCallback(int cacheid,
3638
CacheCallbackFunction func,
3739
Datum arg);

0 commit comments

Comments
 (0)