Commit bd673e8e authored by Tom Lane's avatar Tom Lane

Make sure ALTER TABLE preserves index tablespaces.

When rebuilding an existing index, ALTER TABLE correctly kept the
physical file in the same tablespace, but it messed up the pg_class
entry if the index had been in the database's default tablespace
and "default_tablespace" was set to some non-default tablespace.
This led to an inaccessible index.

Fix by fixing pg_get_indexdef_string() to always include a tablespace
clause, whether or not the index is in the default tablespace.  The
previous behavior was installed in commit 537e92e4, and I think it just
wasn't thought through very clearly; certainly the possible effect of
default_tablespace wasn't considered.  There's some risk in changing the
behavior of this function, but there are no other call sites in the core
code.  Even if it's being used by some third party extension, it's fairly
hard to envision a usage that is okay with a tablespace clause being
appended some of the time but can't handle it being appended all the time.

Back-patch to all supported versions.

Code fix by me, investigation and test cases by Michael Paquier.

Discussion: <1479294998857-5930602.post@n3.nabble.com>
parent e343dfa4
......@@ -1061,7 +1061,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
*
* Note that the SQL-function versions of this omit any info about the
* index tablespace; this is intentional because pg_dump wants it that way.
* However pg_get_indexdef_string() includes index tablespace if not default.
* However pg_get_indexdef_string() includes the index tablespace.
* ----------
*/
Datum
......@@ -1102,7 +1102,11 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(string_to_text(res));
}
/* Internal version that returns a palloc'd C string; no pretty-printing */
/*
* Internal version for use by ALTER TABLE.
* Includes a tablespace clause in the result.
* Returns a palloc'd C string; no pretty-printing.
*/
char *
pg_get_indexdef_string(Oid indexrelid)
{
......@@ -1360,21 +1364,20 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
}
/*
* If it's in a nondefault tablespace, say so, but only if requested
* Print tablespace, but only if requested
*/
if (showTblSpc)
{
Oid tblspc;
tblspc = get_rel_tablespace(indexrelid);
if (OidIsValid(tblspc))
{
if (!OidIsValid(tblspc))
tblspc = MyDatabaseTableSpace;
if (isConstraint)
appendStringInfoString(&buf, " USING INDEX");
appendStringInfo(&buf, " TABLESPACE %s",
quote_identifier(get_tablespace_name(tblspc)));
}
}
/*
* If it's a partial index, decompile and append the predicate
......
......@@ -44,6 +44,37 @@ CREATE INDEX foo_idx on testschema.foo(i) TABLESPACE regress_tblspace;
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo_idx';
-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds
CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace;
INSERT INTO testschema.test_default_tab VALUES (1);
CREATE INDEX test_index1 on testschema.test_default_tab (id);
CREATE INDEX test_index2 on testschema.test_default_tab (id) TABLESPACE regress_tblspace;
\d testschema.test_index1
\d testschema.test_index2
-- use a custom tablespace for default_tablespace
SET default_tablespace TO regress_tblspace;
-- tablespace should not change if no rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
\d testschema.test_index1
\d testschema.test_index2
SELECT * FROM testschema.test_default_tab;
-- tablespace should not change even if there is an index rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
\d testschema.test_index1
\d testschema.test_index2
SELECT * FROM testschema.test_default_tab;
-- now use the default tablespace for default_tablespace
SET default_tablespace TO '';
-- tablespace should not change if no rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
\d testschema.test_index1
\d testschema.test_index2
-- tablespace should not change even if there is an index rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
\d testschema.test_index1
\d testschema.test_index2
DROP TABLE testschema.test_default_tab;
-- let's try moving a table from one place to another
CREATE TABLE testschema.atable AS VALUES (1), (2);
CREATE UNIQUE INDEX anindex ON testschema.atable(column1);
......
......@@ -61,6 +61,111 @@ SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
foo_idx | regress_tblspace
(1 row)
-- check that default_tablespace doesn't affect ALTER TABLE index rebuilds
CREATE TABLE testschema.test_default_tab(id bigint) TABLESPACE regress_tblspace;
INSERT INTO testschema.test_default_tab VALUES (1);
CREATE INDEX test_index1 on testschema.test_default_tab (id);
CREATE INDEX test_index2 on testschema.test_default_tab (id) TABLESPACE regress_tblspace;
\d testschema.test_index1
Index "testschema.test_index1"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
\d testschema.test_index2
Index "testschema.test_index2"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
Tablespace: "regress_tblspace"
-- use a custom tablespace for default_tablespace
SET default_tablespace TO regress_tblspace;
-- tablespace should not change if no rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
\d testschema.test_index1
Index "testschema.test_index1"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
\d testschema.test_index2
Index "testschema.test_index2"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
Tablespace: "regress_tblspace"
SELECT * FROM testschema.test_default_tab;
id
----
1
(1 row)
-- tablespace should not change even if there is an index rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
\d testschema.test_index1
Index "testschema.test_index1"
Column | Type | Definition
--------+---------+------------
id | integer | id
btree, for table "testschema.test_default_tab"
\d testschema.test_index2
Index "testschema.test_index2"
Column | Type | Definition
--------+---------+------------
id | integer | id
btree, for table "testschema.test_default_tab"
Tablespace: "regress_tblspace"
SELECT * FROM testschema.test_default_tab;
id
----
1
(1 row)
-- now use the default tablespace for default_tablespace
SET default_tablespace TO '';
-- tablespace should not change if no rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE int;
\d testschema.test_index1
Index "testschema.test_index1"
Column | Type | Definition
--------+---------+------------
id | integer | id
btree, for table "testschema.test_default_tab"
\d testschema.test_index2
Index "testschema.test_index2"
Column | Type | Definition
--------+---------+------------
id | integer | id
btree, for table "testschema.test_default_tab"
Tablespace: "regress_tblspace"
-- tablespace should not change even if there is an index rewrite
ALTER TABLE testschema.test_default_tab ALTER id TYPE bigint;
\d testschema.test_index1
Index "testschema.test_index1"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
\d testschema.test_index2
Index "testschema.test_index2"
Column | Type | Definition
--------+--------+------------
id | bigint | id
btree, for table "testschema.test_default_tab"
Tablespace: "regress_tblspace"
DROP TABLE testschema.test_default_tab;
-- let's try moving a table from one place to another
CREATE TABLE testschema.atable AS VALUES (1), (2);
CREATE UNIQUE INDEX anindex ON testschema.atable(column1);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment