<para>
<command>ALTER TABLE MERGE PARTITION</command> uses the partitioned
table itself as the template to construct the new partition.
- The new partition will inherit the same table access method, persistence
- type, and tablespace as the partitioned table.
+ The new partition inherits the table access method and persistence type
+ of the partitioned table. Its tablespace is selected as for a
+ <command>CREATE TABLE ... PARTITION OF</command> command issued
+ without a <literal>TABLESPACE</literal> clause: if the partitioned
+ table has an explicit tablespace, the new partition uses it;
+ otherwise the value of <xref linkend="guc-default-tablespace"/> is
+ taken into account, falling back to the database's default tablespace.
Constraints, column defaults, column generation expressions, identity
columns, indexes, and triggers are copied from the partitioned table to
<para>
<command>ALTER TABLE SPLIT PARTITION</command> uses the partitioned
table itself as the template to construct new partitions.
- New partitions will inherit the same table access method, persistence
- type, and tablespace as the partitioned table.
+ New partitions inherit the table access method and persistence type of
+ the partitioned table. Their tablespace is selected as for a
+ <command>CREATE TABLE ... PARTITION OF</command> command issued
+ without a <literal>TABLESPACE</literal> clause: if the partitioned
+ table has an explicit tablespace, the new partitions use it;
+ otherwise the value of <xref linkend="guc-default-tablespace"/> is
+ taken into account, falling back to the database's default tablespace.
</para>
<para>
Relation newRel;
Oid newRelId;
Oid existingRelid;
+ Oid tablespaceId;
TupleDesc descriptor;
List *colList = NIL;
Oid relamId;
errmsg("cannot create a permanent relation as partition of temporary relation \"%s\"",
RelationGetRelationName(parent_rel)));
+ /*
+ * Select the tablespace for the new partition. Mirror the logic that
+ * CREATE TABLE foo PARTITION OF ... uses in DefineRelation: take the
+ * partitioned parent's explicit tablespace if it has one, otherwise take
+ * default_tablespace into account, and finally use the database default.
+ */
+ tablespaceId = parent_relform->reltablespace;
+ if (!OidIsValid(tablespaceId))
+ tablespaceId = GetDefaultTablespace(newPartName->relpersistence, false);
+
+ /* Check permissions except when using database's default */
+ if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
+ {
+ AclResult aclresult;
+
+ aclresult = object_aclcheck(TableSpaceRelationId, tablespaceId,
+ GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_TABLESPACE,
+ get_tablespace_name(tablespaceId));
+ }
+
+ /* In all cases disallow placing user relations in pg_global */
+ if (tablespaceId == GLOBALTABLESPACE_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("only shared relations can be placed in pg_global tablespace")));
+
/* Create the relation. */
newRelId = heap_create_with_catalog(newPartName->relname,
namespaceId,
- parent_relform->reltablespace,
+ tablespaceId,
InvalidOid,
InvalidOid,
InvalidOid,
10000
(1 row)
+DROP TABLE t;
+-- Tablespace selection for the new merged partition mirrors
+-- CREATE TABLE ... PARTITION OF: the partitioned root's explicit
+-- tablespace wins; otherwise default_tablespace applies; otherwise the
+-- database default is used.
+CREATE TABLE t (i int) PARTITION BY RANGE(i) TABLESPACE regress_tblspace;
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+SELECT spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname = 'tp_merged';
+ spcname
+------------------
+ regress_tblspace
+(1 row)
+
+DROP TABLE t;
+-- Parent has no explicit tablespace, but default_tablespace is set: the
+-- new partition lands on default_tablespace.
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+SET default_tablespace TO regress_tblspace;
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+RESET default_tablespace;
+SELECT spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname = 'tp_merged';
+ spcname
+------------------
+ regress_tblspace
+(1 row)
+
+DROP TABLE t;
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+-- pg_global is rejected when picked up from default_tablespace.
+SET default_tablespace TO pg_global;
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged; -- fails
+ERROR: only shared relations can be placed in pg_global tablespace
+RESET default_tablespace;
+-- Parent has no explicit tablespace and default_tablespace is empty: the
+-- new partition uses the database default (reltablespace = 0).
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+SELECT reltablespace FROM pg_class WHERE relname = 'tp_merged';
+ reltablespace
+---------------
+ 0
+(1 row)
+
DROP TABLE t;
RESET search_path;
--
10000
(1 row)
+DROP TABLE t;
+-- Tablespace selection for the new partitions mirrors
+-- CREATE TABLE ... PARTITION OF: the partitioned root's explicit
+-- tablespace wins; otherwise default_tablespace applies; otherwise the
+-- database default is used.
+CREATE TABLE t (i int) PARTITION BY RANGE(i) TABLESPACE regress_tblspace;
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+SELECT c.relname, s.spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname IN ('tp_lo', 'tp_hi')
+ ORDER BY c.relname;
+ relname | spcname
+---------+------------------
+ tp_hi | regress_tblspace
+ tp_lo | regress_tblspace
+(2 rows)
+
+DROP TABLE t;
+-- Parent has no explicit tablespace, but default_tablespace is set: the
+-- new partitions land on default_tablespace.
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+SET default_tablespace TO regress_tblspace;
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+RESET default_tablespace;
+SELECT c.relname, s.spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname IN ('tp_lo', 'tp_hi')
+ ORDER BY c.relname;
+ relname | spcname
+---------+------------------
+ tp_hi | regress_tblspace
+ tp_lo | regress_tblspace
+(2 rows)
+
+DROP TABLE t;
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+-- pg_global is rejected when picked up from default_tablespace.
+SET default_tablespace TO pg_global;
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+); -- fails
+ERROR: only shared relations can be placed in pg_global tablespace
+RESET default_tablespace;
+-- Parent has no explicit tablespace and default_tablespace is empty: new
+-- partitions use the database default (reltablespace = 0).
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+SELECT relname, reltablespace FROM pg_class
+ WHERE relname IN ('tp_lo', 'tp_hi') ORDER BY relname;
+ relname | reltablespace
+---------+---------------
+ tp_hi | 0
+ tp_lo | 0
+(2 rows)
+
DROP TABLE t;
RESET search_path;
--
SELECT length(a) FROM t;
DROP TABLE t;
+-- Tablespace selection for the new merged partition mirrors
+-- CREATE TABLE ... PARTITION OF: the partitioned root's explicit
+-- tablespace wins; otherwise default_tablespace applies; otherwise the
+-- database default is used.
+CREATE TABLE t (i int) PARTITION BY RANGE(i) TABLESPACE regress_tblspace;
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+SELECT spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname = 'tp_merged';
+DROP TABLE t;
+
+-- Parent has no explicit tablespace, but default_tablespace is set: the
+-- new partition lands on default_tablespace.
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+SET default_tablespace TO regress_tblspace;
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+RESET default_tablespace;
+SELECT spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname = 'tp_merged';
+DROP TABLE t;
+
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_0_5 PARTITION OF t FOR VALUES FROM (0) TO (5);
+CREATE TABLE tp_5_10 PARTITION OF t FOR VALUES FROM (5) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+-- pg_global is rejected when picked up from default_tablespace.
+SET default_tablespace TO pg_global;
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged; -- fails
+RESET default_tablespace;
+-- Parent has no explicit tablespace and default_tablespace is empty: the
+-- new partition uses the database default (reltablespace = 0).
+ALTER TABLE t MERGE PARTITIONS (tp_0_5, tp_5_10) INTO tp_merged;
+SELECT reltablespace FROM pg_class WHERE relname = 'tp_merged';
+DROP TABLE t;
+
RESET search_path;
SELECT length(a) FROM t;
DROP TABLE t;
+-- Tablespace selection for the new partitions mirrors
+-- CREATE TABLE ... PARTITION OF: the partitioned root's explicit
+-- tablespace wins; otherwise default_tablespace applies; otherwise the
+-- database default is used.
+CREATE TABLE t (i int) PARTITION BY RANGE(i) TABLESPACE regress_tblspace;
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+SELECT c.relname, s.spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname IN ('tp_lo', 'tp_hi')
+ ORDER BY c.relname;
+DROP TABLE t;
+
+-- Parent has no explicit tablespace, but default_tablespace is set: the
+-- new partitions land on default_tablespace.
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+SET default_tablespace TO regress_tblspace;
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+RESET default_tablespace;
+SELECT c.relname, s.spcname FROM pg_class c LEFT JOIN pg_tablespace s
+ ON c.reltablespace = s.oid WHERE c.relname IN ('tp_lo', 'tp_hi')
+ ORDER BY c.relname;
+DROP TABLE t;
+
+CREATE TABLE t (i int) PARTITION BY RANGE(i);
+CREATE TABLE tp_all PARTITION OF t FOR VALUES FROM (0) TO (10);
+INSERT INTO t SELECT generate_series(0, 9);
+-- pg_global is rejected when picked up from default_tablespace.
+SET default_tablespace TO pg_global;
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+); -- fails
+RESET default_tablespace;
+-- Parent has no explicit tablespace and default_tablespace is empty: new
+-- partitions use the database default (reltablespace = 0).
+ALTER TABLE t SPLIT PARTITION tp_all INTO (
+ PARTITION tp_lo FOR VALUES FROM (0) TO (5),
+ PARTITION tp_hi FOR VALUES FROM (5) TO (10)
+);
+SELECT relname, reltablespace FROM pg_class
+ WHERE relname IN ('tp_lo', 'tp_hi') ORDER BY relname;
+DROP TABLE t;
+
RESET search_path;
--