Index: doc/src/sgml/ref/alter_table.sgml =================================================================== RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/ref/alter_table.sgml,v retrieving revision 1.56 diff -c -r1.56 alter_table.sgml *** doc/src/sgml/ref/alter_table.sgml 2003/02/19 04:06:28 1.56 --- doc/src/sgml/ref/alter_table.sgml 2003/03/09 04:53:41 *************** *** 46,51 **** --- 46,53 ---- DROP CONSTRAINT constraint_name [ RESTRICT | CASCADE ] ALTER TABLE table OWNER TO new_owner + ALTER TABLE table + CLUSTER ON index_name *************** *** 139,144 **** --- 141,155 ---- + index_name + + + The index name on which the table should be marked for clustering. + + + + + CASCADE *************** *** 340,345 **** --- 351,366 ---- This form changes the owner of the table, index, sequence or view to the specified user. + + + + + + CLUSTER + + + This form marks a table for future + operations. Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/tablecmds.c,v retrieving revision 1.67 diff -c -r1.67 tablecmds.c *** src/backend/commands/tablecmds.c 2003/02/13 05:19:59 1.67 --- src/backend/commands/tablecmds.c 2003/03/09 04:53:54 *************** *** 3796,3801 **** --- 3796,3885 ---- } /* + * ALTER TABLE CLUSTER ON + * + * The only thing we have to do is to change the indisclustered bits. + */ + void + AlterTableClusterOn(Oid relOid, const char *indexName) + { + Relation rel, + pg_index; + List *index; + Oid indexOid; + HeapTuple indexTuple; + Form_pg_index indexForm; + + rel = heap_open(relOid, AccessExclusiveLock); + + indexOid = get_relname_relid(indexName, rel->rd_rel->relnamespace); + + if (!OidIsValid(indexOid)) + elog(ERROR, "ALTER TABLE: cannot find index \"%s\" for table \"%s\"", + indexName, NameStr(rel->rd_rel->relname)); + + indexTuple = SearchSysCache(INDEXRELID, + ObjectIdGetDatum(indexOid), + 0, 0, 0); + + if (!HeapTupleIsValid(indexTuple)) + elog(ERROR, "Cache lookup failed for index %u", + indexOid); + indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + + /* + * If this is the same index the relation was previously + * clustered on, no need to do anything. + */ + if (indexForm->indisclustered) + { + elog(NOTICE, "ALTER TABLE: table \"%s\" is already being clustered on index \"%s\"", + NameStr(rel->rd_rel->relname), indexName); + heap_close(rel, AccessExclusiveLock); + return; + } + + pg_index = heap_openr(IndexRelationName, RowExclusiveLock); + + /* + * Now check each index in the relation and set the bit where needed. + */ + foreach (index, RelationGetIndexList(rel)) + { + HeapTuple idxtuple; + Form_pg_index idxForm; + + indexOid = lfirsto(index); + idxtuple = SearchSysCacheCopy(INDEXRELID, + ObjectIdGetDatum(indexOid), + 0, 0, 0); + if (!HeapTupleIsValid(idxtuple)) + elog(ERROR, "Cache lookup failed for index %u", indexOid); + idxForm = (Form_pg_index) GETSTRUCT(idxtuple); + /* + * Unset the bit if set. We know it's wrong because we checked + * this earlier. + */ + if (idxForm->indisclustered) + { + idxForm->indisclustered = false; + simple_heap_update(pg_index, &idxtuple->t_self, idxtuple); + CatalogUpdateIndexes(pg_index, idxtuple); + } + else if (idxForm->indexrelid == indexForm->indexrelid) + { + idxForm->indisclustered = true; + simple_heap_update(pg_index, &idxtuple->t_self, idxtuple); + CatalogUpdateIndexes(pg_index, idxtuple); + } + heap_freetuple(idxtuple); + } + ReleaseSysCache(indexTuple); + heap_close(rel, AccessExclusiveLock); + heap_close(pg_index, RowExclusiveLock); + } + + /* * ALTER TABLE CREATE TOAST TABLE */ void Index: src/backend/parser/gram.y =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/parser/gram.y,v retrieving revision 2.404 diff -c -r2.404 gram.y *** src/backend/parser/gram.y 2003/02/16 02:30:38 2.404 --- src/backend/parser/gram.y 2003/03/09 04:54:06 *************** *** 1214,1219 **** --- 1214,1228 ---- n->name = $6; $$ = (Node *)n; } + /* ALTER TABLE CLUSTER ON */ + | ALTER TABLE qualified_name CLUSTER ON name + { + AlterTableStmt *n = makeNode(AlterTableStmt); + n->subtype = 'L'; + n->relation = $3; + n->name = $6; + $$ = (Node *)n; + } ; alter_column_default: Index: src/backend/tcop/utility.c =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.193 diff -c -r1.193 utility.c *** src/backend/tcop/utility.c 2003/02/19 03:59:02 1.193 --- src/backend/tcop/utility.c 2003/03/09 04:54:11 *************** *** 611,616 **** --- 611,619 ---- AlterTableOwner(relid, get_usesysid(stmt->name)); break; + case 'L': /* CLUSTER ON */ + AlterTableClusterOn(relid, stmt->name); + break; case 'o': /* ADD OIDS */ AlterTableAlterOids(relid, interpretInhOption(stmt->relation->inhOpt), Index: src/include/commands/tablecmds.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/commands/tablecmds.h,v retrieving revision 1.11 diff -c -r1.11 tablecmds.h *** src/include/commands/tablecmds.h 2003/02/13 05:20:03 1.11 --- src/include/commands/tablecmds.h 2003/03/09 04:54:13 *************** *** 43,48 **** --- 43,50 ---- const char *constrName, DropBehavior behavior); + extern void AlterTableClusterOn(Oid relOid, const char *indexName); + extern void AlterTableCreateToastTable(Oid relOid, bool silent); extern void AlterTableOwner(Oid relationOid, int32 newOwnerSysId); Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/include/nodes/parsenodes.h,v retrieving revision 1.231 diff -c -r1.231 parsenodes.h *** src/include/nodes/parsenodes.h 2003/02/16 02:30:39 1.231 --- src/include/nodes/parsenodes.h 2003/03/09 04:54:16 *************** *** 709,714 **** --- 709,715 ---- * X = drop constraint * E = create toast table * U = change owner + * L = CLUSTER ON * o = DROP OIDS *------------ */ Index: src/test/regress/expected/cluster.out =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/expected/cluster.out,v retrieving revision 1.7 diff -c -r1.7 cluster.out *** src/test/regress/expected/cluster.out 2002/12/30 18:42:17 1.7 --- src/test/regress/expected/cluster.out 2003/03/09 04:54:21 *************** *** 285,290 **** --- 285,302 ---- clstr_tst_c (1 row) + -- Try changing indisclustered + ALTER TABLE clstr_tst CLUSTER ON clstr_tst_b_c; + SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2 + WHERE pg_class.oid=indexrelid + AND indrelid=pg_class_2.oid + AND pg_class_2.relname = 'clstr_tst' + AND indisclustered; + relname + --------------- + clstr_tst_b_c + (1 row) + -- Verify that clustering all tables does in fact cluster the right ones CREATE USER clstr_user; CREATE TABLE clstr_1 (a INT PRIMARY KEY); Index: src/test/regress/sql/cluster.sql =================================================================== RCS file: /projects/cvsroot/pgsql-server/src/test/regress/sql/cluster.sql,v retrieving revision 1.6 diff -c -r1.6 cluster.sql *** src/test/regress/sql/cluster.sql 2002/11/19 17:39:00 1.6 --- src/test/regress/sql/cluster.sql 2003/03/09 04:54:22 *************** *** 87,92 **** --- 87,100 ---- AND pg_class_2.relname = 'clstr_tst' AND indisclustered; + -- Try changing indisclustered + ALTER TABLE clstr_tst CLUSTER ON clstr_tst_b_c; + SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2 + WHERE pg_class.oid=indexrelid + AND indrelid=pg_class_2.oid + AND pg_class_2.relname = 'clstr_tst' + AND indisclustered; + -- Verify that clustering all tables does in fact cluster the right ones CREATE USER clstr_user; CREATE TABLE clstr_1 (a INT PRIMARY KEY);