Hi,
Here's a patch to allow TOAST tables to be moved to a different
tablespace. This item has been picked up from the TODO list.
Main idea is to consider that a TOAST table can have its own tablespace.
Regards,
--
JT
diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml
index 00a477e..a2360f4 100644
--- a/doc/src/sgml/ref/alter_table.sgml
+++ b/doc/src/sgml/ref/alter_table.sgml
@@ -66,6 +66,8 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
NOT OF
OWNER TO <replaceable class="PARAMETER">new_owner</replaceable>
SET TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable>
+ SET TABLE TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable>
+ SET TOAST TABLESPACE <replaceable class="PARAMETER">new_tablespace</replaceable>
<phrase>and <replaceable class="PARAMETER">table_constraint_using_index</replaceable> is:</phrase>
@@ -549,6 +551,30 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><literal>SET TABLE TABLESPACE</literal></term>
+ <listitem>
+ <para>
+ This form changes only table's tablespace (not associated TOAST table's tablespace)
+ to the specified tablespace and moves the data file(s) associated to the new tablespace.
+ See also
+ <xref linkend="SQL-CREATETABLESPACE">
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>SET TOAST TABLESPACE</literal></term>
+ <listitem>
+ <para>
+ This form changes the TOAST table's tablespace to the specified tablespace and
+ moves the data file(s) associated with the TOAST table to the new tablespace.
+ See also
+ <xref linkend="SQL-CREATETABLESPACE">
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><literal>RENAME</literal></term>
diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml
index 0a133bb..d7d4235 100644
--- a/doc/src/sgml/storage.sgml
+++ b/doc/src/sgml/storage.sgml
@@ -422,6 +422,11 @@ pages). There was no run time difference compared to an un-<acronym>TOAST</>ed
comparison table, in which all the HTML pages were cut down to 7 kB to fit.
</para>
+<para>
+TOAST table can be moved to a different tablespace with
+<command>ALTER TABLE SET TOAST TABLESPACE</>
+</para>
+
</sect1>
<sect1 id="storage-fsm">
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index a938c98..7ad965e 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -36,7 +36,7 @@ extern Oid binary_upgrade_next_toast_pg_class_oid;
Oid binary_upgrade_next_toast_pg_type_oid = InvalidOid;
static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
- Datum reloptions);
+ Datum reloptions, Oid toastTableSpace);
static bool needs_toast_table(Relation rel);
@@ -53,19 +53,30 @@ static bool needs_toast_table(Relation rel);
* to end with CommandCounterIncrement if it makes any changes.
*/
void
-AlterTableCreateToastTable(Oid relOid, Datum reloptions)
+AlterTableCreateToastTable(Oid relOid, Datum reloptions, Oid toastTableSpace)
{
Relation rel;
-
+ Relation toast_rel;
/*
* Grab a DDL-exclusive lock on the target table, since we'll update the
* pg_class tuple. This is redundant for all present users. Tuple
* toasting behaves safely in the face of a concurrent TOAST table add.
*/
rel = heap_open(relOid, ShareUpdateExclusiveLock);
+
+ /*
+ * if NewToastTableSpace is null then try to find old TOAST table's tablespace
+ */
+ if (!OidIsValid(toastTableSpace) && OidIsValid(rel->rd_rel->reltoastrelid))
+ {
+ toast_rel = relation_open(rel->rd_rel->reltoastrelid, NoLock);
+ if (OidIsValid(toast_rel->rd_rel->reltablespace))
+ toastTableSpace = toast_rel->rd_rel->reltablespace;
+ relation_close(toast_rel, NoLock);
+ }
/* create_toast_table does all the work */
- (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions);
+ (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions, toastTableSpace);
heap_close(rel, NoLock);
}
@@ -91,7 +102,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
relName)));
/* create_toast_table does all the work */
- if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0))
+ if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0,InvalidOid))
elog(ERROR, "\"%s\" does not require a toast table",
relName);
@@ -107,7 +118,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
* bootstrap they can be nonzero to specify hand-assigned OIDs
*/
static bool
-create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions)
+create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptions, Oid toastTableSpace)
{
Oid relOid = RelationGetRelid(rel);
HeapTuple reltup;
@@ -207,10 +218,15 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
toast_typid = binary_upgrade_next_toast_pg_type_oid;
binary_upgrade_next_toast_pg_type_oid = InvalidOid;
}
+
+ /* Use table's tablespace if toastTableSpace is null */
+ if (!OidIsValid(toastTableSpace))
+ toastTableSpace = rel->rd_rel->reltablespace;
+
toast_relid = heap_create_with_catalog(toast_relname,
namespaceid,
- rel->rd_rel->reltablespace,
+ toastTableSpace,
toastOid,
toast_typid,
InvalidOid,
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 8200d20..bd23c8b 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -543,6 +543,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
bool is_system_catalog;
bool swap_toast_by_content;
TransactionId frozenXid;
+ Oid ToastTableSpace;
+ Relation ToastRel;
/* Mark the correct index as clustered */
if (OidIsValid(indexOid))
@@ -551,11 +553,25 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
/* Remember if it's a system catalog */
is_system_catalog = IsSystemRelation(OldHeap);
+ /*
+ * Verifiy if a TOASTed relation exists and is a valid relation
+ * If true, keep its previous tablespace in memory to rebuild it in
+ * the same tablespace
+ */
+ if (OidIsValid(OldHeap->rd_rel->reltoastrelid))
+ {
+ ToastRel = relation_open(OldHeap->rd_rel->reltoastrelid, NoLock);
+ ToastTableSpace = ToastRel->rd_rel->reltablespace;
+ relation_close(ToastRel, NoLock);
+ }
+ else
+ ToastTableSpace = tableSpace;
+
/* Close relcache entry, but keep lock until transaction commit */
heap_close(OldHeap, NoLock);
/* Create the transient table that will receive the re-ordered data */
- OIDNewHeap = make_new_heap(tableOid, tableSpace);
+ OIDNewHeap = make_new_heap(tableOid, tableSpace, ToastTableSpace);
/* Copy the heap data into the new table in the desired order */
copy_heap_data(OIDNewHeap, tableOid, indexOid,
@@ -581,7 +597,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
* data, then call finish_heap_swap to complete the operation.
*/
Oid
-make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
+make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewToastTableSpace)
{
TupleDesc OldHeapDesc;
char NewHeapName[NAMEDATALEN];
@@ -679,7 +695,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
if (isNull)
reloptions = (Datum) 0;
- AlterTableCreateToastTable(OIDNewHeap, reloptions);
+ AlterTableCreateToastTable(OIDNewHeap, reloptions, NewToastTableSpace);
ReleaseSysCache(tuple);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1e8ad2b..fa6d1a8 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -147,7 +147,8 @@ typedef struct AlteredTableInfo
List *newvals; /* List of NewColumnValue */
bool new_notnull; /* T if we added new NOT NULL constraints */
bool rewrite; /* T if a rewrite is forced */
- Oid newTableSpace; /* new tablespace; 0 means no change */
+ Oid newTableSpace; /* new tablespace; 0 means no change */
+ Oid newToastTableSpace; /* new TOAST 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 */
@@ -356,8 +357,11 @@ static void change_owner_recurse_to_sequences(Oid relationOid,
static void ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode);
static void ATExecDropCluster(Relation rel, LOCKMODE lockmode);
static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel,
- char *tablespacename, LOCKMODE lockmode);
-static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
+ char *tablespacename, LOCKMODE lockmode, bool table_only);
+static void ATPrepSetToastTableSpace(AlteredTableInfo *tab, Relation rel,
+ char *tablespacename, LOCKMODE lockmode);
+static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode, Oid newToastTableSpace);
+static void ATExecSetToastTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode);
static void ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode);
static void ATExecEnableDisableTrigger(Relation rel, char *trigname,
char fires_when, bool skip_system, LOCKMODE lockmode);
@@ -2980,7 +2984,19 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
case AT_SetTableSpace: /* SET TABLESPACE */
ATSimplePermissions(rel, ATT_TABLE | ATT_INDEX);
/* This command never recurses */
- ATPrepSetTableSpace(tab, rel, cmd->name, lockmode);
+ ATPrepSetTableSpace(tab, rel, cmd->name, lockmode, false);
+ pass = AT_PASS_MISC; /* doesn't actually matter */
+ break;
+ case AT_SetTableTableSpace: /* SET TABLE TABLESPACE */
+ ATSimplePermissions(rel, ATT_TABLE | ATT_INDEX);
+ /* This command never recurses */
+ ATPrepSetTableSpace(tab, rel, cmd->name, lockmode, true);
+ pass = AT_PASS_MISC; /* doesn't actually matter */
+ break;
+ case AT_SetToastTableSpace: /* SET TOAST TABLESPACE */
+ ATSimplePermissions(rel, ATT_TABLE | ATT_INDEX);
+ /* This command never recurses */
+ ATPrepSetToastTableSpace(tab, rel, cmd->name, lockmode);
pass = AT_PASS_MISC; /* doesn't actually matter */
break;
case AT_SetRelOptions: /* SET (...) */
@@ -3099,7 +3115,7 @@ ATRewriteCatalogs(List **wqueue, LOCKMODE lockmode)
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
if (tab->relkind == RELKIND_RELATION)
- AlterTableCreateToastTable(tab->relid, (Datum) 0);
+ AlterTableCreateToastTable(tab->relid, (Datum) 0, InvalidOid);
}
}
@@ -3227,6 +3243,18 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
* Nothing to do here; Phase 3 does the work
*/
break;
+ case AT_SetTableTableSpace: /* SET TABLE TABLESPACE */
+
+ /*
+ * Nothing to do here; Phase 3 does the work
+ */
+ break;
+ case AT_SetToastTableSpace: /* SET TOAST TABLESPACE */
+
+ /*
+ * Nothing to do here; Phase 3 does the work
+ */
+ break;
case AT_SetRelOptions: /* SET (...) */
ATExecSetRelOptions(rel, (List *) cmd->def, false, lockmode);
break;
@@ -3362,6 +3390,7 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
Relation OldHeap;
Oid OIDNewHeap;
Oid NewTableSpace;
+ Oid NewToastTableSpace;
OldHeap = heap_open(tab->relid, NoLock);
@@ -3393,11 +3422,16 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
NewTableSpace = tab->newTableSpace;
else
NewTableSpace = OldHeap->rd_rel->reltablespace;
+
+ if (tab->newToastTableSpace)
+ NewToastTableSpace = tab->newToastTableSpace;
+ else
+ NewToastTableSpace = InvalidOid;
heap_close(OldHeap, NoLock);
/* Create transient table that will receive the modified data */
- OIDNewHeap = make_new_heap(tab->relid, NewTableSpace);
+ OIDNewHeap = make_new_heap(tab->relid, NewTableSpace, NewToastTableSpace);
/*
* Copy the heap data into the new table with the desired
@@ -3431,7 +3465,9 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
* just do a block-by-block copy.
*/
if (tab->newTableSpace)
- ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode);
+ ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode, tab->newToastTableSpace);
+ if (tab->newToastTableSpace)
+ ATExecSetToastTableSpace(tab->relid, tab->newToastTableSpace, lockmode);
}
}
@@ -8027,30 +8063,66 @@ ATExecDropCluster(Relation rel, LOCKMODE lockmode)
}
/*
- * ALTER TABLE SET TABLESPACE
+ * Check tablespace's permissions & no multiple SET TABLESPACE subcommands
*/
-static void
-ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode)
+extern void CheckTableSpaceAlterTable(char *TableSpaceName, Oid TableSpaceOid, Oid NewTableSpaceOid)
{
- Oid tablespaceId;
AclResult aclresult;
-
- /* Check that the tablespace exists */
- tablespaceId = get_tablespace_oid(tablespacename, false);
-
/* Check its permissions */
- aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ACL_CREATE);
+ aclresult = pg_tablespace_aclcheck(TableSpaceOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_TABLESPACE, tablespacename);
+ aclcheck_error(aclresult, ACL_KIND_TABLESPACE, TableSpaceName);
- /* Save info for Phase 3 to do the real work */
- if (OidIsValid(tab->newTableSpace))
+ if (OidIsValid(NewTableSpaceOid))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cannot have multiple SET TABLESPACE subcommands")));
+}
+
+/*
+ * ALTER TABLE SET [TABLE] TABLESPACE
+ */
+static void
+ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode, bool table_only)
+{
+ Oid tablespaceId;
+
+ /* Check that the tablespace exists */
+ tablespaceId = get_tablespace_oid(tablespacename, false);
+
+ /* Check it */
+ CheckTableSpaceAlterTable(tablespacename, tablespaceId, tab->newTableSpace);
+
+ /* Save tablespace Oid */
tab->newTableSpace = tablespaceId;
+
+ /* The case when we want to move only table location not its TOAST table */
+ if (table_only)
+ tab->newToastTableSpace = 0;
+ else
+ tab->newToastTableSpace = tablespaceId;
+
+}
+
+/*
+ * ALTER TABLE SET TOAST TABLESPACE
+ */
+static void
+ATPrepSetToastTableSpace(AlteredTableInfo *tab, Relation rel, char *tablespacename, LOCKMODE lockmode)
+{
+ Oid tablespaceId;
+
+ /* Check that the tablespace exists */
+ tablespaceId = get_tablespace_oid(tablespacename, false);
+
+ /* Check it */
+ CheckTableSpaceAlterTable(tablespacename, tablespaceId, tab->newToastTableSpace);
+
+ /* Save TOAST tablespace Oid */
+ tab->newToastTableSpace = tablespaceId;
}
+
/*
* ALTER TABLE/INDEX SET (...) or RESET (...)
*/
@@ -8178,12 +8250,42 @@ ATExecSetRelOptions(Relation rel, List *defList, bool isReset, LOCKMODE lockmode
heap_close(pgclass, RowExclusiveLock);
}
+
+extern void
+RelationIsMoveableToNewTablespace(Relation rel, Oid newTableSpace)
+{
+ /*
+ * We cannot support moving mapped relations into different tablespaces.
+ * (In particular this eliminates all shared catalogs.)
+ */
+ if (RelationIsMapped(rel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move system relation \"%s\"",
+ RelationGetRelationName(rel))));
+
+ /* Can't move a non-shared relation into pg_global */
+ if (newTableSpace == GLOBALTABLESPACE_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("only shared relations can be placed in pg_global tablespace")));
+
+ /*
+ * Don't allow moving temp tables of other backends ... their local buffer
+ * manager is not going to cope.
+ */
+ if (RELATION_IS_OTHER_TEMP(rel))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot move temporary tables of other sessions")));
+}
+
/*
- * Execute ALTER TABLE SET TABLESPACE for cases where there is no tuple
+ * Execute ALTER TABLE SET [TABLE] 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, LOCKMODE lockmode)
+ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode, Oid newToastTableSpace)
{
Relation rel;
Oid oldTableSpace;
@@ -8212,31 +8314,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
relation_close(rel, NoLock);
return;
}
-
- /*
- * We cannot support moving mapped relations into different tablespaces.
- * (In particular this eliminates all shared catalogs.)
- */
- if (RelationIsMapped(rel))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot move system relation \"%s\"",
- RelationGetRelationName(rel))));
-
- /* Can't move a non-shared relation into pg_global */
- if (newTableSpace == GLOBALTABLESPACE_OID)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("only shared relations can be placed in pg_global tablespace")));
-
- /*
- * Don't allow moving temp tables of other backends ... their local buffer
- * manager is not going to cope.
- */
- if (RELATION_IS_OTHER_TEMP(rel))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot move temporary tables of other sessions")));
+
+ RelationIsMoveableToNewTablespace(rel, newTableSpace);
reltoastrelid = rel->rd_rel->reltoastrelid;
reltoastidxid = rel->rd_rel->reltoastidxid;
@@ -8316,12 +8395,69 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
CommandCounterIncrement();
/* Move associated toast relation and/or index, too */
- if (OidIsValid(reltoastrelid))
- ATExecSetTableSpace(reltoastrelid, newTableSpace, lockmode);
+ if (newToastTableSpace != 0)
+ {
+ if (OidIsValid(reltoastrelid))
+ ATExecSetTableSpace(reltoastrelid, newToastTableSpace, lockmode, newToastTableSpace);
+ if (OidIsValid(reltoastidxid))
+ ATExecSetTableSpace(reltoastidxid, newToastTableSpace, lockmode, newToastTableSpace);
+ }
+}
+
+
+/*
+ * Execute ALTER TABLE SET TOAST TABLESPACE
+ */
+static void
+ATExecSetToastTableSpace(Oid tableOid, Oid newToastTableSpace, LOCKMODE lockmode)
+{
+ Relation rel;
+ Oid oldToastTableSpace;
+ Oid reltoastrelid;
+ Oid reltoastidxid;
+ Relation relToast;
+ /*
+ * Need lock here in case we are recursing to toast table or index
+ */
+ rel = relation_open(tableOid, lockmode);
+
+ /*
+ * Need to know old TOAST tablespace
+ */
+ if (OidIsValid(rel->rd_rel->reltoastrelid))
+ {
+ relToast = relation_open(rel->rd_rel->reltoastrelid, NoLock);
+
+ oldToastTableSpace = relToast->rd_rel->reltablespace;
+ if (newToastTableSpace == oldToastTableSpace ||
+ (newToastTableSpace == MyDatabaseTableSpace && oldToastTableSpace == 0))
+ {
+ relation_close(rel, NoLock);
+ relation_close(relToast, NoLock);
+ return;
+ }
+ }
+ else
+ {
+ relation_close(rel, NoLock);
+ return;
+ }
+
+ reltoastrelid = rel->rd_rel->reltoastrelid;
+ reltoastidxid = rel->rd_rel->reltoastidxid;
+
+ RelationIsMoveableToNewTablespace(rel, newToastTableSpace);
+
+ relation_close(rel, NoLock);
+ relation_close(relToast, NoLock);
+
+ ATExecSetTableSpace(reltoastrelid, newToastTableSpace, lockmode, newToastTableSpace);
if (OidIsValid(reltoastidxid))
- ATExecSetTableSpace(reltoastidxid, newTableSpace, lockmode);
+ ATExecSetTableSpace(reltoastidxid, newToastTableSpace, lockmode, newToastTableSpace);
+
}
+
/*
* Copy data, block by block
*/
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index fd7a9ed..a5e78bd 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2509,7 +2509,7 @@ OpenIntoRel(QueryDesc *queryDesc)
(void) heap_reloptions(RELKIND_TOASTVALUE, reloptions, true);
- AlterTableCreateToastTable(intoRelationId, reloptions);
+ AlterTableCreateToastTable(intoRelationId, reloptions, InvalidOid);
/*
* And open the constructed table for writing.
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e9f3896..47f8905 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -558,7 +558,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
SYMMETRIC SYSID SYSTEM_P
TABLE TABLES TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP
- TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
+ TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED
@@ -1985,6 +1985,22 @@ alter_table_cmd:
n->name = $3;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> SET TOAST TABLESPACE <tablespacename> */
+ | SET TOAST TABLESPACE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetToastTableSpace;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
+ /* ALTER TABLE <name> SET TABLE TABLESPACE <tablespacename> */
+ | SET TABLE TABLESPACE name
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetTableTableSpace;
+ n->name = $4;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <name> SET (...) */
| SET reloptions
{
@@ -12057,6 +12073,7 @@ unreserved_keyword:
| TEMPLATE
| TEMPORARY
| TEXT_P
+ | TOAST
| TRANSACTION
| TRIGGER
| TRUNCATE
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 0749227..0e65f8e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -552,7 +552,7 @@ standard_ProcessUtility(Node *parsetree,
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
true);
- AlterTableCreateToastTable(relOid, toast_options);
+ AlterTableCreateToastTable(relOid, toast_options, InvalidOid);
}
else if (IsA(stmt, CreateForeignTableStmt))
{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index b4ab19d..86ca6fa 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -3832,6 +3832,7 @@ getTables(int *numTables)
int i_owning_tab;
int i_owning_col;
int i_reltablespace;
+ int i_reltoasttablespace;
int i_reloptions;
int i_toastreloptions;
int i_reloftype;
@@ -3859,7 +3860,44 @@ getTables(int *numTables)
* we cannot correctly identify inherited columns, owned sequences, etc.
*/
- if (g_fout->remoteVersion >= 90100)
+ if (g_fout->remoteVersion >= 90200)
+ {
+ /*
+ * Left join to pick up dependency info linking sequences to their
+ * owning column, if any (note this dependency is AUTO as of 8.2)
+ */
+ appendPQExpBuffer(query,
+ "SELECT c.tableoid, c.oid, c.relname, "
+ "c.relacl, c.relkind, c.relnamespace, "
+ "(%s c.relowner) AS rolname, "
+ "c.relchecks, c.relhastriggers, "
+ "c.relhasindex, c.relhasrules, c.relhasoids, "
+ "c.relfrozenxid, tc.oid AS toid, "
+ "tc.relfrozenxid AS tfrozenxid, "
+ "c.relpersistence, "
+ "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
+ "d.refobjid AS owning_tab, "
+ "d.refobjsubid AS owning_col, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+ "array_to_string(c.reloptions, ', ') AS reloptions, "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, "
+ "(SELECT spcname FROM pg_tablespace t WHERE t.oid = tc.reltablespace) AS reltoasttablespace "
+ "FROM pg_class c "
+ "LEFT JOIN pg_depend d ON "
+ "(c.relkind = '%c' AND "
+ "d.classid = c.tableoid AND d.objid = c.oid AND "
+ "d.objsubid = 0 AND "
+ "d.refclassid = c.tableoid AND d.deptype = 'a') "
+ "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
+ "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
+ "ORDER BY c.oid",
+ username_subquery,
+ RELKIND_SEQUENCE,
+ RELKIND_RELATION, RELKIND_SEQUENCE,
+ RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
+ RELKIND_FOREIGN_TABLE);
+ }
+ else if (g_fout->remoteVersion >= 90100)
{
/*
* Left join to pick up dependency info linking sequences to their
@@ -3879,7 +3917,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
- "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -3915,7 +3954,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
- "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -3950,7 +3990,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
- "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
+ "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -3985,7 +4026,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -4021,7 +4063,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -4056,7 +4099,8 @@ getTables(int *numTables)
"d.refobjsubid AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
@@ -4087,7 +4131,8 @@ getTables(int *numTables)
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class "
"WHERE relkind IN ('%c', '%c', '%c') "
"ORDER BY oid",
@@ -4113,7 +4158,8 @@ getTables(int *numTables)
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class "
"WHERE relkind IN ('%c', '%c', '%c') "
"ORDER BY oid",
@@ -4149,7 +4195,8 @@ getTables(int *numTables)
"NULL::int4 AS owning_col, "
"NULL AS reltablespace, "
"NULL AS reloptions, "
- "NULL AS toast_reloptions "
+ "NULL AS toast_reloptions, "
+ "NULL AS reltoasttablespace "
"FROM pg_class c "
"WHERE relkind IN ('%c', '%c') "
"ORDER BY oid",
@@ -4198,6 +4245,7 @@ getTables(int *numTables)
i_reloptions = PQfnumber(res, "reloptions");
i_toastreloptions = PQfnumber(res, "toast_reloptions");
i_reloftype = PQfnumber(res, "reloftype");
+ i_reltoasttablespace = PQfnumber(res, "reltoasttablespace");
if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
{
@@ -4252,6 +4300,7 @@ getTables(int *numTables)
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
+ tblinfo[i].reltoasttablespace = strdup(PQgetvalue(res, i, i_reltoasttablespace));
/* other fields were zeroed above */
@@ -12518,7 +12567,14 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
}
}
}
-
+ if (strlen(tbinfo->reltoasttablespace) > 0)
+ {
+ appendPQExpBuffer(q, "ALTER TABLE %s ",
+ fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(q, "SET TOAST TABLESPACE %s;\n",
+ tbinfo->reltoasttablespace);
+ }
+
if (binary_upgrade)
binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 3d5d534..dd9cf4c 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -241,6 +241,7 @@ typedef struct _tableInfo
char relkind;
char relpersistence; /* relation persistence */
char *reltablespace; /* relation tablespace */
+ char *reltoasttablespace; /* TOAST relation tablespace */
char *reloptions; /* options specified by WITH (...) */
char *toast_reloptions; /* ditto, for the TOAST table */
bool hasindex; /* does it have any indexes? */
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index d5466f8..d4e8d2c 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -29,6 +29,7 @@ static bool describeOneTableDetails(const char *schemaname,
bool verbose);
static void add_tablespace_footer(printTableContent *const cont, char relkind,
Oid tablespace, const bool newline);
+static void add_toasttablespace_footer(printTableContent *const cont, Oid toasttablespace);
static void add_role_attribute(PQExpBuffer buf, const char *const str);
static bool listTSParsersVerbose(const char *pattern);
static bool describeOneTSParser(const char *oid, const char *nspname,
@@ -1101,6 +1102,7 @@ describeOneTableDetails(const char *schemaname,
bool hastriggers;
bool hasoids;
Oid tablespace;
+ Oid toasttablespace;
char *reloptions;
char *reloftype;
char relpersistence;
@@ -1123,7 +1125,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
"c.relhastriggers, c.relhasoids, "
- "%s, c.reltablespace, "
+ "%s, c.reltablespace, tc.reltablespace, "
"CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
"c.relpersistence\n"
"FROM pg_catalog.pg_class c\n "
@@ -1140,7 +1142,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
"c.relhastriggers, c.relhasoids, "
- "%s, c.reltablespace, "
+ "%s, c.reltablespace, tc.reltablespace, "
"CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END\n"
"FROM pg_catalog.pg_class c\n "
"LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
@@ -1156,7 +1158,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
"c.relhastriggers, c.relhasoids, "
- "%s, c.reltablespace\n"
+ "%s, c.reltablespace, tc.reltablespace\n"
"FROM pg_catalog.pg_class c\n "
"LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
"WHERE c.oid = '%s';",
@@ -1171,7 +1173,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT relchecks, relkind, relhasindex, relhasrules, "
"reltriggers <> 0, relhasoids, "
- "%s, reltablespace\n"
+ "%s, reltablespace, ''\n"
"FROM pg_catalog.pg_class WHERE oid = '%s';",
(verbose ?
"pg_catalog.array_to_string(reloptions, E', ')" : "''"),
@@ -1182,7 +1184,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT relchecks, relkind, relhasindex, relhasrules, "
"reltriggers <> 0, relhasoids, "
- "'', reltablespace\n"
+ "'', reltablespace, ''\n"
"FROM pg_catalog.pg_class WHERE oid = '%s';",
oid);
}
@@ -1191,7 +1193,7 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf,
"SELECT relchecks, relkind, relhasindex, relhasrules, "
"reltriggers <> 0, relhasoids, "
- "'', ''\n"
+ "'', '', ''\n"
"FROM pg_catalog.pg_class WHERE oid = '%s';",
oid);
}
@@ -1219,10 +1221,12 @@ describeOneTableDetails(const char *schemaname,
strdup(PQgetvalue(res, 0, 6)) : 0;
tableinfo.tablespace = (pset.sversion >= 80000) ?
atooid(PQgetvalue(res, 0, 7)) : 0;
- tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ?
- strdup(PQgetvalue(res, 0, 8)) : 0;
- tableinfo.relpersistence = (pset.sversion >= 90100 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
- PQgetvalue(res, 0, 9)[0] : 0;
+ tableinfo.toasttablespace = (pset.sversion >= 80400) ?
+ atooid(PQgetvalue(res, 0, 8)) : 0;
+ tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
+ strdup(PQgetvalue(res, 0, 9)) : 0;
+ tableinfo.relpersistence = (pset.sversion >= 90100 && strcmp(PQgetvalue(res, 0, 10), "") != 0) ?
+ PQgetvalue(res, 0, 10)[0] : 0;
PQclear(res);
res = NULL;
@@ -1567,6 +1571,7 @@ describeOneTableDetails(const char *schemaname,
printTableAddFooter(&cont, tmpbuf.data);
add_tablespace_footer(&cont, tableinfo.relkind,
tableinfo.tablespace, true);
+ add_toasttablespace_footer(&cont, tableinfo.toasttablespace);
}
PQclear(result);
@@ -2171,6 +2176,7 @@ describeOneTableDetails(const char *schemaname,
add_tablespace_footer(&cont, tableinfo.relkind, tableinfo.tablespace,
true);
+ add_toasttablespace_footer(&cont, tableinfo.toasttablespace);
}
printTable(&cont, pset.queryFout, pset.logfile);
@@ -2270,6 +2276,37 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
}
/*
+ * Add a TOAST tablespace description to a footer.
+ */
+static void
+add_toasttablespace_footer(printTableContent *const cont, Oid toasttablespace)
+{
+ if (toasttablespace != 0)
+ {
+ PGresult *result = NULL;
+ PQExpBufferData buf;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT spcname FROM pg_catalog.pg_tablespace\n"
+ "WHERE oid = '%u';", toasttablespace);
+ result = PSQLexec(buf.data, false);
+ if (!result)
+ return;
+ /* Should always be the case, but.... */
+ if (PQntuples(result) > 0)
+ {
+ /* Add the TOAST tablespace as a new footer */
+ printfPQExpBuffer(&buf, _("TOAST Tablespace: \"%s\""),
+ PQgetvalue(result, 0, 0));
+ printTableAddFooter(cont, buf.data);
+ }
+ PQclear(result);
+ termPQExpBuffer(&buf);
+ }
+}
+
+/*
* \du or \dg
*
* Describes roles. Any schema portion of the pattern is ignored.
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 4f7df36..c5f183b 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -811,7 +811,7 @@ psql_completion(char *text, int start, int end)
"GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "OPERATOR",
"ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
"TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
- "USER", "USER MAPPING FOR", "VIEW", NULL};
+ "USER", "USER MAPPING FOR", "VIEW", "TOAST TABLESPACE", "TABLE TABLESPACE", NULL};
COMPLETE_WITH_LIST(list_ALTER);
}
@@ -1285,12 +1285,15 @@ psql_completion(char *text, int start, int end)
completion_info_charp = prev3_wd;
COMPLETE_WITH_QUERY(Query_for_index_of_table);
}
- /* If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE and SCHEMA */
+ /*
+ * If we have TABLE <sth> SET, provide WITHOUT,TABLESPACE, TOAST TABLESPACE,
+ * TABLE TABLESPACE and SCHEMA
+ */
else if (pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
pg_strcasecmp(prev_wd, "SET") == 0)
{
static const char *const list_TABLESET[] =
- {"(", "WITHOUT", "TABLESPACE", "SCHEMA", NULL};
+ {"(", "WITHOUT", "TABLESPACE", "SCHEMA", "TOAST TABLESPACE", "TABLE TABLESPACE", NULL};
COMPLETE_WITH_LIST(list_TABLESET);
}
@@ -1299,6 +1302,16 @@ psql_completion(char *text, int start, int end)
pg_strcasecmp(prev2_wd, "SET") == 0 &&
pg_strcasecmp(prev_wd, "TABLESPACE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
+ /* If we have ALTER TABLE <sth> SET TABLE provide TABLESPACE */
+ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
+ pg_strcasecmp(prev2_wd, "SET") == 0 &&
+ pg_strcasecmp(prev_wd, "TABLE") == 0)
+ {
+ static const char *const list_TABLETABLESPACE[] =
+ {"TABLESPACE", NULL};
+ COMPLETE_WITH_LIST(list_TABLETABLESPACE);
+ }
/* If we have TABLE <sth> SET WITHOUT provide CLUSTER or OIDS */
else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
pg_strcasecmp(prev2_wd, "SET") == 0 &&
diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h
index de3623a..388ce5f 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -17,7 +17,7 @@
/*
* toasting.c prototypes
*/
-extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions);
+extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions, Oid toastTableSpace);
extern void BootstrapToastTable(char *relName,
Oid toastOid, Oid toastIndexOid);
diff --git a/src/include/commands/cluster.h b/src/include/commands/cluster.h
index 518e896..08b6181 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -25,7 +25,7 @@ extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
bool recheck, LOCKMODE lockmode);
extern void mark_index_clustered(Relation rel, Oid indexOid);
-extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
+extern Oid make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewToastTableSpace);
extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
bool is_system_catalog,
bool swap_toast_by_content,
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 333e303..d4aa99c 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -24,6 +24,10 @@ extern Oid DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId);
extern void RemoveRelations(DropStmt *drop);
+extern void RelationIsMoveableToNewTablespace(Relation rel, Oid newTableSpace);
+
+extern void CheckTableSpaceAlterTable(char *TableSpaceName, Oid TableSpaceOid, Oid NewTableSpaceOid);
+
extern void AlterTable(AlterTableStmt *stmt);
extern LOCKMODE AlterTableGetLockLevel(List *cmds);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 9998e2f..89a4f7d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1224,7 +1224,9 @@ typedef enum AlterTableType
AT_DropInherit, /* NO INHERIT parent */
AT_AddOf, /* OF <type_name> */
AT_DropOf, /* NOT OF */
- AT_GenericOptions /* OPTIONS (...) */
+ AT_GenericOptions, /* OPTIONS (...) */
+ AT_SetToastTableSpace, /* SET TOAST TABLESPACE */
+ AT_SetTableTableSpace /* SET TABLE TABLESPACE */
} AlterTableType;
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 12c2faf..1e37f97 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -363,6 +363,7 @@ PG_KEYWORD("then", THEN, RESERVED_KEYWORD)
PG_KEYWORD("time", TIME, COL_NAME_KEYWORD)
PG_KEYWORD("timestamp", TIMESTAMP, COL_NAME_KEYWORD)
PG_KEYWORD("to", TO, RESERVED_KEYWORD)
+PG_KEYWORD("toast",TOAST, UNRESERVED_KEYWORD)
PG_KEYWORD("trailing", TRAILING, RESERVED_KEYWORD)
PG_KEYWORD("transaction", TRANSACTION, UNRESERVED_KEYWORD)
PG_KEYWORD("treat", TREAT, COL_NAME_KEYWORD)
diff --git a/src/test/regress/GNUmakefile b/src/test/regress/GNUmakefile
index 90aea6c..d8904db 100644
--- a/src/test/regress/GNUmakefile
+++ b/src/test/regress/GNUmakefile
@@ -125,7 +125,9 @@ $(top_builddir)/contrib/dummy_seclabel/dummy_seclabel$(DLSUFFIX): $(top_builddir
.PHONY: tablespace-setup
tablespace-setup:
rm -rf ./testtablespace
+ rm -rf ./testtablespace2
mkdir ./testtablespace
+ mkdir ./testtablespace2
##
@@ -170,4 +172,5 @@ clean distclean maintainer-clean: clean-lib
# things created by various check targets
rm -f $(output_files) $(input_files)
rm -rf testtablespace
+ rm -rf testtablespace2
rm -rf $(pg_regress_clean_files)
diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source
index dba96f4..230acaa 100644
--- a/src/test/regress/input/tablespace.source
+++ b/src/test/regress/input/tablespace.source
@@ -11,7 +11,7 @@ ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- ok
CREATE SCHEMA testschema;
-- try a table
-CREATE TABLE testschema.foo (i int) TABLESPACE testspace;
+CREATE TABLE testschema.foo (i int, label varchar) TABLESPACE testspace;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo';
@@ -54,7 +54,21 @@ CREATE TABLE bar (i int) TABLESPACE nosuchspace;
-- Fail, not empty
DROP TABLESPACE testspace;
+-- ALTER TABLE SET TOAST TABLESPACE
+CREATE TABLESPACE testspace2 LOCATION '@testtablespace2@';
+ALTER TABLE testschema.foo SET TOAST TABLESPACE testspace;
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+
+ALTER TABLE testschema.foo SET TOAST TABLESPACE testspace2;
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+
+ALTER TABLE testschema.foo SET TABLESPACE testspace2;
+ALTER TABLE testschema.foo SET TABLE TABLESPACE testspace;
+SELECT spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c WHERE c.reltablespace = t.oid AND c.relname = 'foo';
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+
DROP SCHEMA testschema CASCADE;
-- Should succeed
DROP TABLESPACE testspace;
+DROP TABLESPACE testspace2;
diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source
index 1260c96..324cb07 100644
--- a/src/test/regress/output/tablespace.source
+++ b/src/test/regress/output/tablespace.source
@@ -10,7 +10,7 @@ ALTER TABLESPACE testspace RESET (random_page_cost, seq_page_cost); -- ok
-- create a schema we can use
CREATE SCHEMA testschema;
-- try a table
-CREATE TABLE testschema.foo (i int) TABLESPACE testspace;
+CREATE TABLE testschema.foo (i int, label varchar) TABLESPACE testspace;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo';
relname | spcname
@@ -72,6 +72,36 @@ ERROR: tablespace "nosuchspace" does not exist
-- Fail, not empty
DROP TABLESPACE testspace;
ERROR: tablespace "testspace" is not empty
+-- ALTER TABLE SET TOAST TABLESPACE
+CREATE TABLESPACE testspace2 LOCATION '@testtablespace2@';
+ALTER TABLE testschema.foo SET TOAST TABLESPACE testspace;
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+ spcname
+-----------
+ testspace
+(1 row)
+
+ALTER TABLE testschema.foo SET TOAST TABLESPACE testspace2;
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+ spcname
+------------
+ testspace2
+(1 row)
+
+ALTER TABLE testschema.foo SET TABLESPACE testspace2;
+ALTER TABLE testschema.foo SET TABLE TABLESPACE testspace;
+SELECT spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c WHERE c.reltablespace = t.oid AND c.relname = 'foo';
+ spcname
+-----------
+ testspace
+(1 row)
+
+SELECT spcname FROM pg_class c JOIN pg_class d ON (c.reltoastrelid=d.oid) JOIN pg_tablespace ON (d.reltablespace = pg_tablespace.oid) WHERE c.relname = 'foo';
+ spcname
+------------
+ testspace2
+(1 row)
+
DROP SCHEMA testschema CASCADE;
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to table testschema.foo
@@ -80,3 +110,4 @@ drop cascades to table testschema.asexecute
drop cascades to table testschema.atable
-- Should succeed
DROP TABLESPACE testspace;
+DROP TABLESPACE testspace2;
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index d9cd053..5ea6099 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -421,6 +421,7 @@ static void
convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
{
char testtablespace[MAXPGPATH];
+ char testtablespace2[MAXPGPATH];
char indir[MAXPGPATH];
struct stat st;
int ret;
@@ -447,6 +448,7 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
exit_nicely(2);
snprintf(testtablespace, MAXPGPATH, "%s/testtablespace", outputdir);
+ snprintf(testtablespace2, MAXPGPATH, "%s/testtablespace2", outputdir);
#ifdef WIN32
@@ -463,6 +465,9 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
if (directory_exists(testtablespace))
rmtree(testtablespace, true);
make_directory(testtablespace);
+ if (directory_exists(testtablespace2))
+ rmtree(testtablespace2, true);
+ make_directory(testtablespace2);
#endif
/* finally loop on each file and do the replacement */
@@ -507,6 +512,7 @@ convert_sourcefiles_in(char *source_subdir, char *dest_subdir, char *suffix)
replace_string(line, "@abs_srcdir@", inputdir);
replace_string(line, "@abs_builddir@", outputdir);
replace_string(line, "@testtablespace@", testtablespace);
+ replace_string(line, "@testtablespace2@", testtablespace2);
replace_string(line, "@libdir@", dlpath);
replace_string(line, "@DLSUFFIX@", DLSUFFIX);
fputs(line, outfile);
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers