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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy