]> granicus.if.org Git - postgresql/commitdiff
Make sure ALTER TABLE preserves index tablespaces.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 23 Nov 2016 18:45:55 +0000 (13:45 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 23 Nov 2016 18:45:55 +0000 (13:45 -0500)
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 537e92e41, 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>

src/backend/utils/adt/ruleutils.c
src/test/regress/input/tablespace.source
src/test/regress/output/tablespace.source

index a3a4174abfb7924b6d8527c3d96559b5c069175c..fecee85e5bae20a27fb365ecf1eab499e71674ca 100644 (file)
@@ -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,20 +1364,19 @@ 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 (isConstraint)
-                                       appendStringInfoString(&buf, " USING INDEX");
-                               appendStringInfo(&buf, " TABLESPACE %s",
-                                                         quote_identifier(get_tablespace_name(tblspc)));
-                       }
+                       if (!OidIsValid(tblspc))
+                               tblspc = MyDatabaseTableSpace;
+                       if (isConstraint)
+                               appendStringInfoString(&buf, " USING INDEX");
+                       appendStringInfo(&buf, " TABLESPACE %s",
+                                                        quote_identifier(get_tablespace_name(tblspc)));
                }
 
                /*
index 041ec974008789d7db394f2288101c57ed3d8cda..2e676e9cc74ec8c006e0ec1bde2a8f3f549e0760 100644 (file)
@@ -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);
index 384f689ac1030d1895591240c2b4ab945abcaca3..6e0dfd187bda92386c203491ca10df8bce99ba49 100644 (file)
@@ -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);