diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index ef8b57e0ebe75155535283f2f85ea45b17af383a..263e5024b62148863c139a523222af253871288a 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.72 2004/06/02 21:04:40 momjian Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.73 2004/07/11 23:13:51 tgl Exp $ PostgreSQL documentation --> @@ -39,10 +39,11 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } ADD <replaceable class="PARAMETER">table_constraint</replaceable> DROP CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ] - SET WITHOUT OIDS - OWNER TO <replaceable class="PARAMETER">new_owner</replaceable> CLUSTER ON <replaceable class="PARAMETER">index_name</replaceable> SET WITHOUT CLUSTER + SET WITHOUT OIDS + OWNER TO <replaceable class="PARAMETER">new_owner</replaceable> + SET TABLESPACE <replaceable class="PARAMETER">tablespace_name</replaceable> </synopsis> </refsynopsisdiv> @@ -181,6 +182,29 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: </listitem> </varlistentry> + <varlistentry> + <term><literal>CLUSTER</literal></term> + <listitem> + <para> + This form selects the default index for future + <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title"> + operations. It does not actually re-cluster the table. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>SET WITHOUT CLUSTER</literal></term> + <listitem> + <para> + This form removes the most recently used + <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title"> + index specification from the table. This affects + future cluster operations that don't specify an index. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>SET WITHOUT OIDS</literal></term> <listitem> @@ -211,28 +235,19 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: </varlistentry> <varlistentry> - <term><literal>CLUSTER</literal></term> + <term><literal>SET TABLESPACE</literal></term> <listitem> <para> - This form selects the default index for future - <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title"> - operations. + This form changes the table's tablespace to the specified tablespace and + moves the data file(s) associated with the table to the new tablespace. + Indexes on the table, if any, are not moved; but they can be moved + separately with additional <literal>SET TABLESPACE</literal> commands. + See also + <xref linkend="SQL-CREATETABLESPACE" endterm="sql-createtablespace-title">. </para> </listitem> </varlistentry> - <varlistentry> - <term><literal>SET WITHOUT CLUSTER</literal></term> - <listitem> - <para> - This form removes the most recently used - <xref linkend="SQL-CLUSTER" endterm="sql-cluster-title"> - index specification from the table. This affects - future cluster operations that don't specify an index. - </para> - </listitem> - </varlistentry> - <varlistentry> <term><literal>RENAME</literal></term> <listitem> @@ -293,29 +308,29 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: </varlistentry> <varlistentry> - <term><replaceable class="PARAMETER">type</replaceable></term> + <term><replaceable class="PARAMETER">new_column</replaceable></term> <listitem> <para> - Data type of the new column, or new data type for an existing - column. + New name for an existing column. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="PARAMETER">new_column</replaceable></term> + <term><replaceable class="PARAMETER">new_name</replaceable></term> <listitem> <para> - New name for an existing column. + New name for the table. </para> </listitem> </varlistentry> <varlistentry> - <term><replaceable class="PARAMETER">new_name</replaceable></term> + <term><replaceable class="PARAMETER">type</replaceable></term> <listitem> <para> - New name for the table. + Data type of the new column, or new data type for an existing + column. </para> </listitem> </varlistentry> @@ -339,10 +354,21 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: </varlistentry> <varlistentry> - <term><replaceable class="PARAMETER">new_owner</replaceable></term> + <term><literal>CASCADE</literal></term> <listitem> <para> - The user name of the new owner of the table. + Automatically drop objects that depend on the dropped column + or constraint (for example, views referencing the column). + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>RESTRICT</literal></term> + <listitem> + <para> + Refuse to drop the column or constraint if there are any dependent + objects. This is the default behavior. </para> </listitem> </varlistentry> @@ -357,21 +383,19 @@ where <replaceable class="PARAMETER">action</replaceable> is one of: </varlistentry> <varlistentry> - <term><literal>CASCADE</literal></term> + <term><replaceable class="PARAMETER">new_owner</replaceable></term> <listitem> <para> - Automatically drop objects that depend on the dropped column - or constraint (for example, views referencing the column). + The user name of the new owner of the table. </para> </listitem> </varlistentry> <varlistentry> - <term><literal>RESTRICT</literal></term> + <term><replaceable class="PARAMETER">tablespace_name</replaceable></term> <listitem> <para> - Refuse to drop the column or constraint if there are any dependent - objects. This is the default behavior. + The tablespace name to which the table will be moved. </para> </listitem> </varlistentry> @@ -551,6 +575,14 @@ ALTER TABLE distributors ADD CONSTRAINT dist_id_zipcode_key UNIQUE (dist_id, zip ALTER TABLE distributors ADD PRIMARY KEY (dist_id); </programlisting> </para> + + <para> + To move a table to a different tablespace: +<programlisting> +ALTER TABLE distributors SET TABLESPACE fasttablespace; +</programlisting> + </para> + </refsect1> <refsect1> diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index d81771c7a043d11825eac041d9f59bb40a25ed83..391504fb37d1f6b62825c54329e75734bda83c19 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.126 2004/06/18 06:13:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.127 2004/07/11 23:13:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -485,6 +485,7 @@ static void rebuild_relation(Relation OldHeap, Oid indexOid) { Oid tableOid = RelationGetRelid(OldHeap); + Oid tableSpace = OldHeap->rd_rel->reltablespace; Oid OIDNewHeap; char NewHeapName[NAMEDATALEN]; ObjectAddress object; @@ -505,7 +506,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid) */ snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", tableOid); - OIDNewHeap = make_new_heap(tableOid, NewHeapName); + OIDNewHeap = make_new_heap(tableOid, NewHeapName, tableSpace); /* * We don't need CommandCounterIncrement() because make_new_heap did @@ -520,8 +521,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid) /* To make the new heap's data visible (probably not needed?). */ CommandCounterIncrement(); - /* Swap the relfilenodes of the old and new heaps. */ - swap_relfilenodes(tableOid, OIDNewHeap); + /* Swap the physical files of the old and new heaps. */ + swap_relation_files(tableOid, OIDNewHeap); CommandCounterIncrement(); @@ -550,7 +551,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid) * Create the new table that we will fill with correctly-ordered data. */ Oid -make_new_heap(Oid OIDOldHeap, const char *NewName) +make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace) { TupleDesc OldHeapDesc, tupdesc; @@ -568,7 +569,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName) OIDNewHeap = heap_create_with_catalog(NewName, RelationGetNamespace(OldHeap), - OldHeap->rd_rel->reltablespace, + NewTableSpace, tupdesc, OldHeap->rd_rel->relkind, OldHeap->rd_rel->relisshared, @@ -646,13 +647,16 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex) } /* - * Swap the relfilenodes for two given relations. + * Swap the physical files of two given relations. + * + * We swap the physical identity (reltablespace and relfilenode) while + * keeping the same logical identities of the two relations. * * Also swap any TOAST links, so that the toast data moves along with * the main-table data. */ void -swap_relfilenodes(Oid r1, Oid r2) +swap_relation_files(Oid r1, Oid r2) { Relation relRelation, rel; @@ -695,12 +699,16 @@ swap_relfilenodes(Oid r1, Oid r2) relation_close(rel, NoLock); /* - * Actually swap the filenode and TOAST fields in the two tuples + * Actually swap the fields in the two tuples */ swaptemp = relform1->relfilenode; relform1->relfilenode = relform2->relfilenode; relform2->relfilenode = swaptemp; + swaptemp = relform1->reltablespace; + relform1->reltablespace = relform2->reltablespace; + relform2->reltablespace = swaptemp; + swaptemp = relform1->reltoastrelid; relform1->reltoastrelid = relform2->reltoastrelid; relform2->reltoastrelid = swaptemp; @@ -793,13 +801,16 @@ swap_relfilenodes(Oid r1, Oid r2) /* * Blow away the old relcache entries now. We need this kluge because - * relcache.c indexes relcache entries by rd_node as well as OID. It - * will get confused if it is asked to (re)build an entry with a new - * rd_node value when there is still another entry laying about with - * that same rd_node value. (Fortunately, since one of the entries is - * local in our transaction, it's sufficient to clear out our own - * relcache this way; the problem cannot arise for other backends when - * they see our update on the non-local relation.) + * relcache.c keeps a link to the smgr relation for the physical file, + * and that will be out of date as soon as we do CommandCounterIncrement. + * Whichever of the rels is the second to be cleared during cache + * invalidation will have a dangling reference to an already-deleted smgr + * relation. Rather than trying to avoid this by ordering operations + * just so, it's easiest to not have the relcache entries there at all. + * (Fortunately, since one of the entries is local in our transaction, + * it's sufficient to clear out our own relcache this way; the problem + * cannot arise for other backends when they see our update on the + * non-local relation.) */ RelationForgetRelation(r1); RelationForgetRelation(r2); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 392822abf503c785587920a8ca9a74f9089ea00d..a5a7deadcfd5933b33cfca936efe4d3db0837916 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.118 2004/07/01 00:50:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.119 2004/07/11 23:13:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,6 +52,7 @@ #include "parser/parse_relation.h" #include "parser/parse_type.h" #include "rewrite/rewriteHandler.h" +#include "storage/smgr.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/fmgroids.h" @@ -120,6 +121,7 @@ typedef struct AlteredTableInfo /* Information saved by Phases 1/2 for Phase 3: */ List *constraints; /* List of NewConstraint */ List *newvals; /* List of NewColumnValue */ + Oid newTableSpace; /* new tablespace; 0 means no change */ /* Objects to rebuild after completing ALTER TYPE operations */ List *changedConstraintOids; /* OIDs of constraints to rebuild */ List *changedConstraintDefs; /* string definitions of same */ @@ -237,6 +239,10 @@ static void ATPostAlterTypeParse(char *cmd, List **wqueue); static void ATExecChangeOwner(Oid relationOid, int32 newOwnerSysId); static void ATExecClusterOn(Relation rel, const char *indexName); static void ATExecDropCluster(Relation rel); +static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, + char *tablespacename); +static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace); +static void copy_relation_data(Relation rel, SMgrRelation dst); static int ri_trigger_type(Oid tgfoid); static void update_ri_trigger_args(Oid relid, const char *oldname, @@ -1946,6 +1952,11 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, } pass = AT_PASS_DROP; break; + case AT_SetTableSpace: /* SET TABLESPACE */ + /* This command never recurses */ + ATPrepSetTableSpace(tab, rel, cmd->name); + pass = AT_PASS_MISC; /* doesn't actually matter */ + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -2097,6 +2108,11 @@ ATExecCmd(AlteredTableInfo *tab, Relation rel, AlterTableCmd *cmd) * to do the real work */ break; + case AT_SetTableSpace: /* SET TABLESPACE */ + /* + * Nothing to do here; Phase 3 does the work + */ + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); @@ -2132,6 +2148,7 @@ ATRewriteTables(List **wqueue) /* Build a temporary relation and copy data */ Oid OIDNewHeap; char NewHeapName[NAMEDATALEN]; + Oid NewTableSpace; Relation OldHeap; ObjectAddress object; @@ -2157,6 +2174,15 @@ ATRewriteTables(List **wqueue) (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot rewrite temporary tables of other sessions"))); + /* + * Select destination tablespace (same as original unless user + * requested a change) + */ + if (tab->newTableSpace) + NewTableSpace = tab->newTableSpace; + else + NewTableSpace = OldHeap->rd_rel->reltablespace; + heap_close(OldHeap, NoLock); /* @@ -2170,7 +2196,7 @@ ATRewriteTables(List **wqueue) snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", tab->relid); - OIDNewHeap = make_new_heap(tab->relid, NewHeapName); + OIDNewHeap = make_new_heap(tab->relid, NewHeapName, NewTableSpace); /* * Copy the heap data into the new table with the desired @@ -2179,8 +2205,8 @@ ATRewriteTables(List **wqueue) */ ATRewriteTable(tab, OIDNewHeap); - /* Swap the relfilenodes of the old and new heaps. */ - swap_relfilenodes(tab->relid, OIDNewHeap); + /* Swap the physical files of the old and new heaps. */ + swap_relation_files(tab->relid, OIDNewHeap); CommandCounterIncrement(); @@ -2203,13 +2229,20 @@ ATRewriteTables(List **wqueue) */ reindex_relation(tab->relid, false); } - else if (tab->constraints != NIL) + else { /* * Test the current data within the table against new constraints * generated by ALTER TABLE commands, but don't rebuild data. */ - ATRewriteTable(tab, InvalidOid); + if (tab->constraints != NIL) + ATRewriteTable(tab, InvalidOid); + /* + * If we had SET TABLESPACE but no reason to reconstruct tuples, + * just do a block-by-block copy. + */ + if (tab->newTableSpace) + ATExecSetTableSpace(tab->relid, tab->newTableSpace); } } @@ -5185,6 +5218,249 @@ ATExecDropCluster(Relation rel) mark_index_clustered(rel, InvalidOid); } +/* + * ALTER TABLE SET TABLESPACE + */ +static void +ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename) +{ + Oid tablespaceId; + AclResult aclresult; + + /* + * We do our own permission checking because we want to allow this on + * indexes. + */ + if (rel->rd_rel->relkind != RELKIND_RELATION && + rel->rd_rel->relkind != RELKIND_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or index", + RelationGetRelationName(rel)))); + + /* Permissions checks */ + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(rel)); + + if (!allowSystemTableMods && IsSystemRelation(rel)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + RelationGetRelationName(rel)))); + + /* Check that the tablespace exists */ + tablespaceId = get_tablespace_oid(tablespacename); + if (!OidIsValid(tablespaceId)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", tablespacename))); + + /* Check its permissions */ + aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename); + + /* Save info for Phase 3 to do the real work */ + if (OidIsValid(tab->newTableSpace)) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple SET TABLESPACE subcommands are not valid"))); + tab->newTableSpace = tablespaceId; +} + +/* + * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple + * rewriting to be done, so we just want to copy the data as fast as possible. + */ +static void +ATExecSetTableSpace(Oid tableOid, Oid newTableSpace) +{ + Relation rel; + Oid oldTableSpace; + Oid reltoastrelid; + Oid reltoastidxid; + RelFileNode newrnode; + SMgrRelation dstrel; + Relation pg_class; + HeapTuple tuple; + Form_pg_class rd_rel; + + rel = relation_open(tableOid, NoLock); + + /* + * We can never allow moving of shared or nailed-in-cache relations, + * because we can't support changing their reltablespace values. + */ + if (rel->rd_rel->relisshared || rel->rd_isnailed) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move system relation \"%s\"", + RelationGetRelationName(rel)))); + + /* + * Don't allow moving temp tables of other backends ... their + * local buffer manager is not going to cope. + */ + if (isOtherTempNamespace(RelationGetNamespace(rel))) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot move temporary tables of other sessions"))); + + /* + * No work if no change in tablespace. + */ + oldTableSpace = rel->rd_rel->reltablespace; + if (newTableSpace == oldTableSpace || + (newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0)) + { + relation_close(rel, NoLock); + return; + } + + reltoastrelid = rel->rd_rel->reltoastrelid; + reltoastidxid = rel->rd_rel->reltoastidxid; + + /* Get a modifiable copy of the relation's pg_class row */ + pg_class = heap_openr(RelationRelationName, RowExclusiveLock); + + tuple = SearchSysCacheCopy(RELOID, + ObjectIdGetDatum(tableOid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", tableOid); + rd_rel = (Form_pg_class) GETSTRUCT(tuple); + + /* create another storage file. Is it a little ugly ? */ + /* NOTE: any conflict in relfilenode value will be caught here */ + newrnode = rel->rd_node; + newrnode.spcNode = newTableSpace; + + dstrel = smgropen(newrnode); + smgrcreate(dstrel, rel->rd_istemp, false); + + /* schedule unlinking old physical file */ + if (rel->rd_smgr == NULL) + rel->rd_smgr = smgropen(rel->rd_node); + smgrscheduleunlink(rel->rd_smgr, rel->rd_istemp); + + /* copy relation data to the new physical file */ + copy_relation_data(rel, dstrel); + + /* + * Now drop smgr references. We need not smgrclose() the old file, + * since it will be dropped anyway at commit by the pending unlink. + * We do need to get rid of relcache's reference to it, however. + */ + smgrclose(dstrel); + rel->rd_smgr = NULL; + + /* update the pg_class row */ + rd_rel->reltablespace = (newTableSpace == MyDatabaseTableSpace) ? InvalidOid : newTableSpace; + simple_heap_update(pg_class, &tuple->t_self, tuple); + CatalogUpdateIndexes(pg_class, tuple); + + heap_freetuple(tuple); + + heap_close(pg_class, RowExclusiveLock); + + relation_close(rel, NoLock); + + /* Make sure the reltablespace change is visible */ + CommandCounterIncrement(); + + /* Move associated toast relation and/or index, too */ + if (OidIsValid(reltoastrelid)) + ATExecSetTableSpace(reltoastrelid, newTableSpace); + if (OidIsValid(reltoastidxid)) + ATExecSetTableSpace(reltoastidxid, newTableSpace); +} + +/* + * Copy data, block by block + */ +static void +copy_relation_data(Relation rel, SMgrRelation dst) +{ + SMgrRelation src = rel->rd_smgr; + bool use_wal; + BlockNumber nblocks; + BlockNumber blkno; + char buf[BLCKSZ]; + Page page = (Page) buf; + + /* + * Since we copy the data directly without looking at the shared buffers, + * we'd better first flush out any pages of the source relation that are + * in shared buffers. We assume no new pages will get loaded into + * buffers while we are holding exclusive lock on the rel. + */ + FlushRelationBuffers(rel, 0); + + /* + * We need to log the copied data in WAL iff WAL archiving is enabled + * AND it's not a temp rel. + * + * XXX when WAL archiving is actually supported, this test will likely + * need to change; and the hardwired extern is cruddy anyway ... + */ + { + extern char XLOG_archive_dir[]; + + use_wal = XLOG_archive_dir[0] && !rel->rd_istemp; + } + + nblocks = RelationGetNumberOfBlocks(rel); + for (blkno = 0; blkno < nblocks; blkno++) + { + smgrread(src, blkno, buf); + + /* XLOG stuff */ + if (use_wal) + { + xl_heap_newpage xlrec; + XLogRecPtr recptr; + XLogRecData rdata[2]; + + /* NO ELOG(ERROR) from here till newpage op is logged */ + START_CRIT_SECTION(); + + xlrec.node = dst->smgr_rnode; + xlrec.blkno = blkno; + + rdata[0].buffer = InvalidBuffer; + rdata[0].data = (char *) &xlrec; + rdata[0].len = SizeOfHeapNewpage; + rdata[0].next = &(rdata[1]); + + rdata[1].buffer = InvalidBuffer; + rdata[1].data = (char *) page; + rdata[1].len = BLCKSZ; + rdata[1].next = NULL; + + recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata); + + PageSetLSN(page, recptr); + PageSetSUI(page, ThisStartUpID); + + END_CRIT_SECTION(); + } + + /* + * Now write the page. If not using WAL, say isTemp = true, to + * suppress duplicate fsync. If we are using WAL, it surely isn't a + * temp rel, so !use_wal is a sufficient condition. + */ + smgrwrite(dst, blkno, buf, !use_wal); + } + + /* + * If we weren't using WAL, and the rel isn't temp, we must fsync it + * down to disk before it's safe to commit the transaction. + */ + if (!use_wal && !rel->rd_istemp) + smgrimmedsync(dst); +} /* * ALTER TABLE CREATE TOAST TABLE diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7446bc612d5d2f16fc33efcbdd8ea815515663c0..e9af75baaa376af864060055322adb96f970bb1d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.465 2004/06/28 01:19:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.466 2004/07/11 23:13:54 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1286,6 +1286,14 @@ alter_table_cmd: n->name = NULL; $$ = (Node *)n; } + /* ALTER TABLE <name> SET TABLESPACE <tablespacename> */ + | SET TABLESPACE name + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetTableSpace; + n->name = $3; + $$ = (Node *)n; + } ; alter_column_default: diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h index 820c95210805adfbcc60fd469fcb163bd897f00e..11e8a391817e0cc8b46683b39cb0e27457ac8e87 100644 --- a/src/include/commands/cluster.h +++ b/src/include/commands/cluster.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994-5, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.23 2004/05/08 00:34:49 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/cluster.h,v 1.24 2004/07/11 23:13:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,7 +21,8 @@ extern void cluster(ClusterStmt *stmt); extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid); extern void mark_index_clustered(Relation rel, Oid indexOid); -extern Oid make_new_heap(Oid OIDOldHeap, const char *NewName); -extern void swap_relfilenodes(Oid r1, Oid r2); +extern Oid make_new_heap(Oid OIDOldHeap, const char *NewName, + Oid NewTableSpace); +extern void swap_relation_files(Oid r1, Oid r2); #endif /* CLUSTER_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 22d18ef4f70e665dda8e583d83ad2390a4e3d8f4..3745972bd50b496e0fefe204456adb8400a8448f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.260 2004/06/25 21:55:59 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.261 2004/07/11 23:13:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -806,7 +806,8 @@ typedef enum AlterTableType AT_ChangeOwner, /* change owner */ AT_ClusterOn, /* CLUSTER ON */ AT_DropCluster, /* SET WITHOUT CLUSTER */ - AT_DropOids /* SET WITHOUT OIDS */ + AT_DropOids, /* SET WITHOUT OIDS */ + AT_SetTableSpace /* SET TABLESPACE */ } AlterTableType; typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ @@ -814,7 +815,7 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ NodeTag type; AlterTableType subtype; /* Type of table alteration to apply */ char *name; /* column or constraint name to act on, or - * new owner */ + * new owner or tablespace */ Node *def; /* definition of new column, column type, * index, or constraint */ Node *transform; /* transformation expr for ALTER TYPE */