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);