diff --git a/doc/src/sgml/ref/alter_index.sgml b/doc/src/sgml/ref/alter_index.sgml index 94a7af0429c..ee3e3de4d6f 100644 --- a/doc/src/sgml/ref/alter_index.sgml +++ b/doc/src/sgml/ref/alter_index.sgml @@ -25,6 +25,8 @@ ALTER INDEX [ IF EXISTS ] name RENA ALTER INDEX [ IF EXISTS ] name SET TABLESPACE tablespace_name ALTER INDEX [ IF EXISTS ] name SET ( storage_parameter = value [, ... ] ) ALTER INDEX [ IF EXISTS ] name RESET ( storage_parameter [, ... ] ) +ALTER INDEX ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ] + SET TABLESPACE new_tablespace [ NOWAIT ] @@ -63,6 +65,17 @@ ALTER INDEX [ IF EXISTS ] name RESE This form changes the index's tablespace to the specified tablespace and moves the data file(s) associated with the index to the new tablespace. + To change the tablespace of an index, you must own the index and have + CREATE privilege on the new tablespace. + All indexes in the current database in a tablespace can be moved by using + the ALL IN TABLESPACE form, which will lock all + indexes to be moved and then move each one. This form also supports + OWNED BY, which will only move indexes owned by the + roles specified. If the NOWAIT option is specified + then the command will fail if it is unable to acquire all of the locks + required immediately. Note that system catalogs will not be moved by + this command, use ALTER DATABASE or explicit + ALTER INDEX invocations instead if desired. See also . diff --git a/doc/src/sgml/ref/alter_materialized_view.sgml b/doc/src/sgml/ref/alter_materialized_view.sgml index 1932eeb84d4..b0759fc5dca 100644 --- a/doc/src/sgml/ref/alter_materialized_view.sgml +++ b/doc/src/sgml/ref/alter_materialized_view.sgml @@ -29,6 +29,8 @@ ALTER MATERIALIZED VIEW [ IF EXISTS ] namenew_name ALTER MATERIALIZED VIEW [ IF EXISTS ] name SET SCHEMA new_schema +ALTER MATERIALIZED VIEW ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ] + SET TABLESPACE new_tablespace [ NOWAIT ] where action is one of: diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 69a1e14bce3..0e7b99c934c 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -31,6 +31,8 @@ ALTER TABLE [ IF EXISTS ] name RENAME TO new_name ALTER TABLE [ IF EXISTS ] name SET SCHEMA new_schema +ALTER TABLE ALL IN TABLESPACE name [ OWNED BY role_name [, ... ] ] + SET TABLESPACE new_tablespace [ NOWAIT ] where action is one of: @@ -597,6 +599,17 @@ ALTER TABLE [ IF EXISTS ] name 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 SET TABLESPACE commands. + All tables in the current database in a tablespace can be moved by using + the ALL IN TABLESPACE form, which will lock all tables + to be moved first and then move each one. This form also supports + OWNED BY, which will only move tables owned by the + roles specified. If the NOWAIT option is specified + then the command will fail if it is unable to acquire all of the locks + required immediately. Note that system catalogs are not moved by this + command, use ALTER DATABASE or explicit + ALTER TABLE invocations instead if desired. The + information_schema relations are not considered part + of the system catalogs and will be moved. See also . @@ -649,7 +662,8 @@ ALTER TABLE [ IF EXISTS ] name - All the actions except RENAME and SET SCHEMA + All the actions except RENAME, + SET TABLESPACE and SET SCHEMA can be combined into a list of multiple alterations to apply in parallel. For example, it is possible to add several columns and/or alter the type of several @@ -659,8 +673,8 @@ ALTER TABLE [ IF EXISTS ] name You must own the table to use ALTER TABLE. - To change the schema of a table, you must also have - CREATE privilege on the new schema. + To change the schema or tablespace of a table, you must also have + CREATE privilege on the new schema or tablespace. To add the table as a new child of a parent table, you must own the parent table as well. To alter the owner, you must also be a direct or indirect member of the new diff --git a/doc/src/sgml/ref/alter_tablespace.sgml b/doc/src/sgml/ref/alter_tablespace.sgml index bd1afb4b727..7c4aabc5826 100644 --- a/doc/src/sgml/ref/alter_tablespace.sgml +++ b/doc/src/sgml/ref/alter_tablespace.sgml @@ -25,7 +25,6 @@ ALTER TABLESPACE name RENAME TO new_name ALTER TABLESPACE name OWNER TO new_owner ALTER TABLESPACE name SET ( tablespace_option = value [, ... ] ) ALTER TABLESPACE name RESET ( tablespace_option [, ... ] ) -ALTER TABLESPACE name MOVE { ALL | TABLES | INDEXES | MATERIALIZED VIEWS } [ OWNED BY role_name [, ...] ] TO new_tablespace [ NOWAIT ] @@ -45,44 +44,6 @@ ALTER TABLESPACE name MOVE { ALL | TABLES | INDEXES | (Note that superusers have these privileges automatically.) - - ALTER TABLESPACE ... MOVE moves objects between - tablespaces. ALL will move all tables, indexes and - materialized views; specifying TABLES will move only - tables (but not their indexes), INDEXES will only move - indexes (including those underneath materialized views, but not tables), - and MATERIALIZED VIEWS will only move the table relation - of the materialized view (but no indexes associated with it). Users can - also specify a list of roles whose objects are to be moved, using - OWNED BY. - - - - Users must have CREATE rights on the new tablespace and - be considered an owner (either directly or indirectly) of all objects to be - moved. Note that the superuser is considered an owner of all objects, and - therefore an ALTER TABLESPACE ... MOVE ALL issued by the - superuser will move all objects in the current database that are in the - tablespace. (Attempting to move objects without the required rights will - result in an error. Non-superusers can use OWNED BY in - such cases, to restrict the set of objects moved to those with the required - rights.) - - - - All objects to be moved will be locked immediately by the command. If the - NOWAIT is specified, it will cause the command to fail - if it is unable to acquire the locks. - - - - System catalogs will not be moved by this command. To move a whole - database, use ALTER DATABASE, or call ALTER - TABLE on the individual system catalogs. Note that relations in - information_schema will be moved, just as any other - normal database objects, if the user is the superuser or considered an - owner of the relations in information_schema. - @@ -136,38 +97,6 @@ ALTER TABLESPACE name MOVE { ALL | TABLES | INDEXES | - - role_name - - - Role whose objects are to be moved. - - - - - - new_tablespace - - - The name of the tablespace to move objects into. The user must have - CREATE rights on the new tablespace to move objects into that - tablespace, unless the tablespace being moved into is the default - tablespace for the database connected to. - - - - - - NOWAIT - - - The NOWAIT option causes the ALTER TABLESPACE command to fail immediately - if it is unable to acquire the necessary lock on all of the objects being - moved. - - - - @@ -185,13 +114,6 @@ ALTER TABLESPACE index_space RENAME TO fast_raid; Change the owner of tablespace index_space: ALTER TABLESPACE index_space OWNER TO mary; - - - - Move all of the objects from the default tablespace to - the fast_raid tablespace: - -ALTER TABLESPACE pg_default MOVE ALL TO fast_raid; diff --git a/doc/src/sgml/release-9.4.sgml b/doc/src/sgml/release-9.4.sgml index e338554995d..5233ed256ae 100644 --- a/doc/src/sgml/release-9.4.sgml +++ b/doc/src/sgml/release-9.4.sgml @@ -1224,7 +1224,10 @@ Allow moving groups of objects from one tablespace to another - using ... MOVE + using ALL IN TABLESPACE ... SET TABLESPACE with + ALTER TABLE + ALTER INDEX and + ALTER MATERIALIZED VIEW (Stephen Frost) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 89bd31ab93e..34c38de3fff 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -51,6 +51,7 @@ #include "commands/tablespace.h" #include "commands/trigger.h" #include "commands/typecmds.h" +#include "commands/user.h" #include "executor/executor.h" #include "foreign/foreign.h" #include "miscadmin.h" @@ -9204,6 +9205,176 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode) list_free(reltoastidxids); } +/* + * Alter Table ALL ... SET TABLESPACE + * + * Allows a user to move all objects of some type in a given tablespace in the + * current database to another tablespace. Objects can be chosen based on the + * owner of the object also, to allow users to move only their objects. + * The user must have CREATE rights on the new tablespace, as usual. The main + * permissions handling is done by the lower-level table move function. + * + * All to-be-moved objects are locked first. If NOWAIT is specified and the + * lock can't be acquired then we ereport(ERROR). + */ +Oid +AlterTableMoveAll(AlterTableMoveAllStmt *stmt) +{ + List *relations = NIL; + ListCell *l; + ScanKeyData key[1]; + Relation rel; + HeapScanDesc scan; + HeapTuple tuple; + Oid orig_tablespaceoid; + Oid new_tablespaceoid; + List *role_oids = roleNamesToIds(stmt->roles); + + /* Ensure we were not asked to move something we can't */ + if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX && + stmt->objtype != OBJECT_MATVIEW) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("only tables, indexes, and materialized views exist in tablespaces"))); + + /* Get the orig and new tablespace OIDs */ + orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false); + new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false); + + /* Can't move shared relations in to or out of pg_global */ + /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */ + if (orig_tablespaceoid == GLOBALTABLESPACE_OID || + new_tablespaceoid == GLOBALTABLESPACE_OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot move relations in to or out of pg_global tablespace"))); + + /* + * Must have CREATE rights on the new tablespace, unless it is the + * database default tablespace (which all users implicitly have CREATE + * rights on). + */ + if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace) + { + AclResult aclresult; + + aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(), + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, + get_tablespace_name(new_tablespaceoid)); + } + + /* + * Now that the checks are done, check if we should set either to + * InvalidOid because it is our database's default tablespace. + */ + if (orig_tablespaceoid == MyDatabaseTableSpace) + orig_tablespaceoid = InvalidOid; + + if (new_tablespaceoid == MyDatabaseTableSpace) + new_tablespaceoid = InvalidOid; + + /* no-op */ + if (orig_tablespaceoid == new_tablespaceoid) + return new_tablespaceoid; + + /* + * Walk the list of objects in the tablespace and move them. This will + * only find objects in our database, of course. + */ + ScanKeyInit(&key[0], + Anum_pg_class_reltablespace, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(orig_tablespaceoid)); + + rel = heap_open(RelationRelationId, AccessShareLock); + scan = heap_beginscan_catalog(rel, 1, key); + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Oid relOid = HeapTupleGetOid(tuple); + Form_pg_class relForm; + + relForm = (Form_pg_class) GETSTRUCT(tuple); + + /* + * Do not move objects in pg_catalog as part of this, if an admin + * really wishes to do so, they can issue the individual ALTER + * commands directly. + * + * Also, explicitly avoid any shared tables, temp tables, or TOAST + * (TOAST will be moved with the main table). + */ + if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared || + isAnyTempNamespace(relForm->relnamespace) || + relForm->relnamespace == PG_TOAST_NAMESPACE) + continue; + + /* Only move the object type requested */ + if ((stmt->objtype == OBJECT_TABLE && + relForm->relkind != RELKIND_RELATION) || + (stmt->objtype == OBJECT_INDEX && + relForm->relkind != RELKIND_INDEX) || + (stmt->objtype == OBJECT_MATVIEW && + relForm->relkind != RELKIND_MATVIEW)) + continue; + + /* Check if we are only moving objects owned by certain roles */ + if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner)) + continue; + + /* + * Handle permissions-checking here since we are locking the tables + * and also to avoid doing a bunch of work only to fail part-way. Note + * that permissions will also be checked by AlterTableInternal(). + * + * Caller must be considered an owner on the table to move it. + */ + if (!pg_class_ownercheck(relOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + NameStr(relForm->relname)); + + if (stmt->nowait && + !ConditionalLockRelationOid(relOid, AccessExclusiveLock)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_IN_USE), + errmsg("aborting due to \"%s\".\"%s\" --- lock not available", + get_namespace_name(relForm->relnamespace), + NameStr(relForm->relname)))); + else + LockRelationOid(relOid, AccessExclusiveLock); + + /* Add to our list of objects to move */ + relations = lappend_oid(relations, relOid); + } + + heap_endscan(scan); + heap_close(rel, AccessShareLock); + + if (relations == NIL) + ereport(NOTICE, + (errcode(ERRCODE_NO_DATA_FOUND), + errmsg("no matching relations in tablespace \"%s\" found", + orig_tablespaceoid == InvalidOid ? "(database default)" : + get_tablespace_name(orig_tablespaceoid)))); + + /* Everything is locked, loop through and move all of the relations. */ + foreach(l, relations) + { + List *cmds = NIL; + AlterTableCmd *cmd = makeNode(AlterTableCmd); + + cmd->subtype = AT_SetTableSpace; + cmd->name = stmt->new_tablespacename; + + cmds = lappend(cmds, cmd); + + AlterTableInternal(lfirst_oid(l), cmds, false); + } + + return new_tablespaceoid; +} + /* * Copy data, block by block */ diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 031be37a1e7..28e69a55510 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -67,7 +67,6 @@ #include "commands/seclabel.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" -#include "commands/user.h" #include "miscadmin.h" #include "postmaster/bgwriter.h" #include "storage/fd.h" @@ -991,184 +990,6 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) return tablespaceoid; } -/* - * Alter table space move - * - * Allows a user to move all of their objects in a given tablespace in the - * current database to another tablespace. Only objects which the user is - * considered to be an owner of are moved and the user must have CREATE rights - * on the new tablespace. These checks should mean that ALTER TABLE will never - * fail due to permissions, but note that permissions will also be checked at - * that level. Objects can be ALL, TABLES, INDEXES, or MATERIALIZED VIEWS. - * - * All to-be-moved objects are locked first. If NOWAIT is specified and the - * lock can't be acquired then we ereport(ERROR). - */ -Oid -AlterTableSpaceMove(AlterTableSpaceMoveStmt *stmt) -{ - List *relations = NIL; - ListCell *l; - ScanKeyData key[1]; - Relation rel; - HeapScanDesc scan; - HeapTuple tuple; - Oid orig_tablespaceoid; - Oid new_tablespaceoid; - List *role_oids = roleNamesToIds(stmt->roles); - - /* Ensure we were not asked to move something we can't */ - if (!stmt->move_all && stmt->objtype != OBJECT_TABLE && - stmt->objtype != OBJECT_INDEX && stmt->objtype != OBJECT_MATVIEW) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("only tables, indexes, and materialized views exist in tablespaces"))); - - /* Get the orig and new tablespace OIDs */ - orig_tablespaceoid = get_tablespace_oid(stmt->orig_tablespacename, false); - new_tablespaceoid = get_tablespace_oid(stmt->new_tablespacename, false); - - /* Can't move shared relations in to or out of pg_global */ - /* This is also checked by ATExecSetTableSpace, but nice to stop earlier */ - if (orig_tablespaceoid == GLOBALTABLESPACE_OID || - new_tablespaceoid == GLOBALTABLESPACE_OID) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("cannot move relations in to or out of pg_global tablespace"))); - - /* - * Must have CREATE rights on the new tablespace, unless it is the - * database default tablespace (which all users implicitly have CREATE - * rights on). - */ - if (OidIsValid(new_tablespaceoid) && new_tablespaceoid != MyDatabaseTableSpace) - { - AclResult aclresult; - - aclresult = pg_tablespace_aclcheck(new_tablespaceoid, GetUserId(), - ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_TABLESPACE, - get_tablespace_name(new_tablespaceoid)); - } - - /* - * Now that the checks are done, check if we should set either to - * InvalidOid because it is our database's default tablespace. - */ - if (orig_tablespaceoid == MyDatabaseTableSpace) - orig_tablespaceoid = InvalidOid; - - if (new_tablespaceoid == MyDatabaseTableSpace) - new_tablespaceoid = InvalidOid; - - /* no-op */ - if (orig_tablespaceoid == new_tablespaceoid) - return new_tablespaceoid; - - /* - * Walk the list of objects in the tablespace and move them. This will - * only find objects in our database, of course. - */ - ScanKeyInit(&key[0], - Anum_pg_class_reltablespace, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(orig_tablespaceoid)); - - rel = heap_open(RelationRelationId, AccessShareLock); - scan = heap_beginscan_catalog(rel, 1, key); - while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - Oid relOid = HeapTupleGetOid(tuple); - Form_pg_class relForm; - - relForm = (Form_pg_class) GETSTRUCT(tuple); - - /* - * Do not move objects in pg_catalog as part of this, if an admin - * really wishes to do so, they can issue the individual ALTER - * commands directly. - * - * Also, explicitly avoid any shared tables, temp tables, or TOAST - * (TOAST will be moved with the main table). - */ - if (IsSystemNamespace(relForm->relnamespace) || relForm->relisshared || - isAnyTempNamespace(relForm->relnamespace) || - relForm->relnamespace == PG_TOAST_NAMESPACE) - continue; - - /* Only consider objects which live in tablespaces */ - if (relForm->relkind != RELKIND_RELATION && - relForm->relkind != RELKIND_INDEX && - relForm->relkind != RELKIND_MATVIEW) - continue; - - /* Check if we were asked to only move a certain type of object */ - if (!stmt->move_all && - ((stmt->objtype == OBJECT_TABLE && - relForm->relkind != RELKIND_RELATION) || - (stmt->objtype == OBJECT_INDEX && - relForm->relkind != RELKIND_INDEX) || - (stmt->objtype == OBJECT_MATVIEW && - relForm->relkind != RELKIND_MATVIEW))) - continue; - - /* Check if we are only moving objects owned by certain roles */ - if (role_oids != NIL && !list_member_oid(role_oids, relForm->relowner)) - continue; - - /* - * Handle permissions-checking here since we are locking the tables - * and also to avoid doing a bunch of work only to fail part-way. Note - * that permissions will also be checked by AlterTableInternal(). - * - * Caller must be considered an owner on the table to move it. - */ - if (!pg_class_ownercheck(relOid, GetUserId())) - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - NameStr(relForm->relname)); - - if (stmt->nowait && - !ConditionalLockRelationOid(relOid, AccessExclusiveLock)) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_IN_USE), - errmsg("aborting due to \"%s\".\"%s\" --- lock not available", - get_namespace_name(relForm->relnamespace), - NameStr(relForm->relname)))); - else - LockRelationOid(relOid, AccessExclusiveLock); - - /* Add to our list of objects to move */ - relations = lappend_oid(relations, relOid); - } - - heap_endscan(scan); - heap_close(rel, AccessShareLock); - - if (relations == NIL) - ereport(NOTICE, - (errcode(ERRCODE_NO_DATA_FOUND), - errmsg("no matching relations in tablespace \"%s\" found", - orig_tablespaceoid == InvalidOid ? "(database default)" : - get_tablespace_name(orig_tablespaceoid)))); - - /* Everything is locked, loop through and move all of the relations. */ - foreach(l, relations) - { - List *cmds = NIL; - AlterTableCmd *cmd = makeNode(AlterTableCmd); - - cmd->subtype = AT_SetTableSpace; - cmd->name = stmt->new_tablespacename; - - cmds = lappend(cmds, cmd); - - AlterTableInternal(lfirst_oid(l), cmds, false); - } - - return new_tablespaceoid; -} - /* * Routines for handling the GUC variable 'default_tablespace'. */ diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 43530aa24a8..221d0fee6bb 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3402,14 +3402,13 @@ _copyAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *from) return newnode; } -static AlterTableSpaceMoveStmt * -_copyAlterTableSpaceMoveStmt(const AlterTableSpaceMoveStmt *from) +static AlterTableMoveAllStmt * +_copyAlterTableMoveAllStmt(const AlterTableMoveAllStmt *from) { - AlterTableSpaceMoveStmt *newnode = makeNode(AlterTableSpaceMoveStmt); + AlterTableMoveAllStmt *newnode = makeNode(AlterTableMoveAllStmt); COPY_STRING_FIELD(orig_tablespacename); COPY_SCALAR_FIELD(objtype); - COPY_SCALAR_FIELD(move_all); COPY_NODE_FIELD(roles); COPY_STRING_FIELD(new_tablespacename); COPY_SCALAR_FIELD(nowait); @@ -4428,8 +4427,8 @@ copyObject(const void *from) case T_AlterTableSpaceOptionsStmt: retval = _copyAlterTableSpaceOptionsStmt(from); break; - case T_AlterTableSpaceMoveStmt: - retval = _copyAlterTableSpaceMoveStmt(from); + case T_AlterTableMoveAllStmt: + retval = _copyAlterTableMoveAllStmt(from); break; case T_CreateExtensionStmt: retval = _copyCreateExtensionStmt(from); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 2407cb73a38..7e53681e706 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1638,12 +1638,11 @@ _equalAlterTableSpaceOptionsStmt(const AlterTableSpaceOptionsStmt *a, } static bool -_equalAlterTableSpaceMoveStmt(const AlterTableSpaceMoveStmt *a, - const AlterTableSpaceMoveStmt *b) +_equalAlterTableMoveAllStmt(const AlterTableMoveAllStmt *a, + const AlterTableMoveAllStmt *b) { COMPARE_STRING_FIELD(orig_tablespacename); COMPARE_SCALAR_FIELD(objtype); - COMPARE_SCALAR_FIELD(move_all); COMPARE_NODE_FIELD(roles); COMPARE_STRING_FIELD(new_tablespacename); COMPARE_SCALAR_FIELD(nowait); @@ -2896,8 +2895,8 @@ equal(const void *a, const void *b) case T_AlterTableSpaceOptionsStmt: retval = _equalAlterTableSpaceOptionsStmt(a, b); break; - case T_AlterTableSpaceMoveStmt: - retval = _equalAlterTableSpaceMoveStmt(a, b); + case T_AlterTableMoveAllStmt: + retval = _equalAlterTableMoveAllStmt(a, b); break; case T_CreateExtensionStmt: retval = _equalCreateExtensionStmt(a, b); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7b9895d61ec..2e9bbe232f9 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1748,6 +1748,28 @@ AlterTableStmt: n->missing_ok = true; $$ = (Node *)n; } + | ALTER TABLE ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $6; + n->objtype = OBJECT_TABLE; + n->roles = NIL; + n->new_tablespacename = $9; + n->nowait = $10; + $$ = (Node *)n; + } + | ALTER TABLE ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $6; + n->objtype = OBJECT_TABLE; + n->roles = $9; + n->new_tablespacename = $12; + n->nowait = $13; + $$ = (Node *)n; + } | ALTER INDEX qualified_name alter_table_cmds { AlterTableStmt *n = makeNode(AlterTableStmt); @@ -1766,6 +1788,28 @@ AlterTableStmt: n->missing_ok = true; $$ = (Node *)n; } + | ALTER INDEX ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $6; + n->objtype = OBJECT_INDEX; + n->roles = NIL; + n->new_tablespacename = $9; + n->nowait = $10; + $$ = (Node *)n; + } + | ALTER INDEX ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $6; + n->objtype = OBJECT_INDEX; + n->roles = $9; + n->new_tablespacename = $12; + n->nowait = $13; + $$ = (Node *)n; + } | ALTER SEQUENCE qualified_name alter_table_cmds { AlterTableStmt *n = makeNode(AlterTableStmt); @@ -1820,6 +1864,28 @@ AlterTableStmt: n->missing_ok = true; $$ = (Node *)n; } + | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $7; + n->objtype = OBJECT_MATVIEW; + n->roles = NIL; + n->new_tablespacename = $10; + n->nowait = $11; + $$ = (Node *)n; + } + | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name OWNED BY role_list SET TABLESPACE name opt_nowait + { + AlterTableMoveAllStmt *n = + makeNode(AlterTableMoveAllStmt); + n->orig_tablespacename = $7; + n->objtype = OBJECT_MATVIEW; + n->roles = $10; + n->new_tablespacename = $13; + n->nowait = $14; + $$ = (Node *)n; + } ; alter_table_cmds: @@ -6941,103 +7007,8 @@ opt_force: FORCE { $$ = TRUE; } * *****************************************************************************/ -AlterTblSpcStmt: ALTER TABLESPACE name MOVE ALL TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = -1; - n->move_all = true; - n->roles = NIL; - n->new_tablespacename = $7; - n->nowait = $8; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE TABLES TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_TABLE; - n->move_all = false; - n->roles = NIL; - n->new_tablespacename = $7; - n->nowait = $8; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE INDEXES TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_INDEX; - n->move_all = false; - n->roles = NIL; - n->new_tablespacename = $7; - n->nowait = $8; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE MATERIALIZED VIEWS TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_MATVIEW; - n->move_all = false; - n->roles = NIL; - n->new_tablespacename = $8; - n->nowait = $9; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE ALL OWNED BY role_list TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = -1; - n->move_all = true; - n->roles = $8; - n->new_tablespacename = $10; - n->nowait = $11; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE TABLES OWNED BY role_list TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_TABLE; - n->move_all = false; - n->roles = $8; - n->new_tablespacename = $10; - n->nowait = $11; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE INDEXES OWNED BY role_list TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_INDEX; - n->move_all = false; - n->roles = $8; - n->new_tablespacename = $10; - n->nowait = $11; - $$ = (Node *)n; - } - | ALTER TABLESPACE name MOVE MATERIALIZED VIEWS OWNED BY role_list TO name opt_nowait - { - AlterTableSpaceMoveStmt *n = - makeNode(AlterTableSpaceMoveStmt); - n->orig_tablespacename = $3; - n->objtype = OBJECT_MATVIEW; - n->move_all = false; - n->roles = $9; - n->new_tablespacename = $11; - n->nowait = $12; - $$ = (Node *)n; - } - | ALTER TABLESPACE name SET reloptions +AlterTblSpcStmt: + ALTER TABLESPACE name SET reloptions { AlterTableSpaceOptionsStmt *n = makeNode(AlterTableSpaceOptionsStmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 3423898c112..0558ea34b05 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -147,6 +147,7 @@ check_xact_readonly(Node *parsetree) case T_AlterObjectSchemaStmt: case T_AlterOwnerStmt: case T_AlterSeqStmt: + case T_AlterTableMoveAllStmt: case T_AlterTableStmt: case T_RenameStmt: case T_CommentStmt: @@ -200,7 +201,6 @@ check_xact_readonly(Node *parsetree) case T_AlterUserMappingStmt: case T_DropUserMappingStmt: case T_AlterTableSpaceOptionsStmt: - case T_AlterTableSpaceMoveStmt: case T_CreateForeignTableStmt: case T_SecLabelStmt: PreventCommandIfReadOnly(CreateCommandTag(parsetree)); @@ -506,9 +506,8 @@ standard_ProcessUtility(Node *parsetree, AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree); break; - case T_AlterTableSpaceMoveStmt: - /* no event triggers for global objects */ - AlterTableSpaceMove((AlterTableSpaceMoveStmt *) parsetree); + case T_AlterTableMoveAllStmt: + AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree); break; case T_TruncateStmt: @@ -1805,10 +1804,6 @@ CreateCommandTag(Node *parsetree) tag = "ALTER TABLESPACE"; break; - case T_AlterTableSpaceMoveStmt: - tag = "ALTER TABLESPACE"; - break; - case T_CreateExtensionStmt: tag = "CREATE EXTENSION"; break; @@ -1973,6 +1968,10 @@ CreateCommandTag(Node *parsetree) tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType); break; + case T_AlterTableMoveAllStmt: + tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype); + break; + case T_AlterTableStmt: tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind); break; @@ -2501,10 +2500,6 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; - case T_AlterTableSpaceMoveStmt: - lev = LOGSTMT_DDL; - break; - case T_CreateExtensionStmt: case T_AlterExtensionStmt: case T_AlterExtensionContentsStmt: @@ -2583,6 +2578,7 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_AlterTableMoveAllStmt: case T_AlterTableStmt: lev = LOGSTMT_DDL; break; diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index e55f45ab26f..932322f144c 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -35,6 +35,8 @@ extern void ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, L extern void AlterTableInternal(Oid relid, List *cmds, bool recurse); +extern Oid AlterTableMoveAll(AlterTableMoveAllStmt *stmt); + extern Oid AlterTableNamespace(AlterObjectSchemaStmt *stmt); extern void AlterTableNamespaceInternal(Relation rel, Oid oldNspOid, diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 1603f677a7d..c7af55917d7 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -43,7 +43,6 @@ extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt); extern void DropTableSpace(DropTableSpaceStmt *stmt); extern Oid RenameTableSpace(const char *oldname, const char *newname); extern Oid AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt); -extern Oid AlterTableSpaceMove(AlterTableSpaceMoveStmt *stmt); extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index bc58e165258..5dcc66f27ff 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -354,7 +354,7 @@ typedef enum NodeTag T_AlterUserMappingStmt, T_DropUserMappingStmt, T_AlterTableSpaceOptionsStmt, - T_AlterTableSpaceMoveStmt, + T_AlterTableMoveAllStmt, T_SecLabelStmt, T_CreateForeignTableStmt, T_CreateExtensionStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 7e560a19a3b..3146aa53ed1 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1689,16 +1689,15 @@ typedef struct AlterTableSpaceOptionsStmt bool isReset; } AlterTableSpaceOptionsStmt; -typedef struct AlterTableSpaceMoveStmt +typedef struct AlterTableMoveAllStmt { NodeTag type; char *orig_tablespacename; - ObjectType objtype; /* set to -1 if move_all is true */ - bool move_all; /* move all, or just objtype objects? */ + ObjectType objtype; /* Object type to move */ List *roles; /* List of roles to move objects of */ char *new_tablespacename; bool nowait; -} AlterTableSpaceMoveStmt; +} AlterTableMoveAllStmt; /* ---------------------- * Create/Alter Extension Statements diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source index 601522866d1..e259254b02c 100644 --- a/src/test/regress/input/tablespace.source +++ b/src/test/regress/input/tablespace.source @@ -76,10 +76,11 @@ CREATE TABLE tablespace_table (i int) TABLESPACE testspace; -- fail ALTER TABLESPACE testspace RENAME TO testspace_renamed; -ALTER TABLESPACE testspace_renamed MOVE ALL TO pg_default; +ALTER TABLE ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; +ALTER INDEX ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; -- Should show notice that nothing was done -ALTER TABLESPACE testspace_renamed MOVE ALL TO pg_default; +ALTER TABLE ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; -- Should succeed DROP TABLESPACE testspace_renamed; diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source index 27bc491e195..a30651087b9 100644 --- a/src/test/regress/output/tablespace.source +++ b/src/test/regress/output/tablespace.source @@ -93,9 +93,10 @@ CREATE TABLE tablespace_table (i int) TABLESPACE testspace; -- fail ERROR: permission denied for tablespace testspace \c - ALTER TABLESPACE testspace RENAME TO testspace_renamed; -ALTER TABLESPACE testspace_renamed MOVE ALL TO pg_default; +ALTER TABLE ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; +ALTER INDEX ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; -- Should show notice that nothing was done -ALTER TABLESPACE testspace_renamed MOVE ALL TO pg_default; +ALTER TABLE ALL IN TABLESPACE testspace_renamed SET TABLESPACE pg_default; NOTICE: no matching relations in tablespace "testspace_renamed" found -- Should succeed DROP TABLESPACE testspace_renamed; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 913d6ef6b28..ab36aa3acb6 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -77,7 +77,7 @@ AlterSystemStmt AlterTSConfigurationStmt AlterTSDictionaryStmt AlterTableCmd -AlterTableSpaceMoveStmt +AlterTableMoveAllStmt AlterTableSpaceOptionsStmt AlterTableStmt AlterTableType