Fix ALTER COLUMN TYPE to preserve the tablespace and reloptions of indexes
authorTom Lane <[email protected]>
Sat, 13 Oct 2007 15:55:58 +0000 (15:55 +0000)
committerTom Lane <[email protected]>
Sat, 13 Oct 2007 15:55:58 +0000 (15:55 +0000)
it affects.  The original coding neglected tablespace entirely (causing
the indexes to move to the database's default tablespace) and for an index
belonging to a UNIQUE or PRIMARY KEY constraint, it would actually try to
assign the parent table's reloptions to the index :-(.  Per bug #3672 and
subsequent investigation.

8.0 and 8.1 did not have reloptions, but the tablespace bug is present.

src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/lsyscache.c
src/include/utils/lsyscache.h

index 613d7982456a69cfb5aee3409a086a902584eb09..ba24ba96f6c7351f713507202b0e168050058f0e 100644 (file)
@@ -54,6 +54,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_trigger.h"
+#include "commands/tablespace.h"
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "lib/stringinfo.h"
@@ -157,12 +158,13 @@ static char *pg_get_viewdef_worker(Oid viewoid, int prettyFlags);
 static void decompile_column_index_array(Datum column_index_array, Oid relId,
                                                         StringInfo buf);
 static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
-static char *pg_get_indexdef_worker(Oid indexrelid, int colno,
+static char *pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
                                           int prettyFlags);
 static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                                                        int prettyFlags);
 static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
                                   int prettyFlags);
+static Oid     get_constraint_index(Oid constraintId);
 static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
                         int prettyFlags);
 static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
@@ -596,6 +598,10 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
  * In the extended version, there is a colno argument as well as pretty bool.
  *     if colno == 0, we want a complete index definition.
  *     if colno > 0, we only want the Nth index key's variable or expression.
+ *
+ * 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.
  * ----------
  */
 Datum
@@ -603,7 +609,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
 {
        Oid                     indexrelid = PG_GETARG_OID(0);
 
-       PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0, 0)));
+       PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, 0,
+                                                                                                                  false, 0)));
 }
 
 Datum
@@ -615,18 +622,20 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
        int                     prettyFlags;
 
        prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
-       PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno, prettyFlags)));
+       PG_RETURN_TEXT_P(string_to_text(pg_get_indexdef_worker(indexrelid, colno,
+                                                                                                                false, prettyFlags)));
 }
 
 /* Internal version that returns a palloc'd C string */
 char *
 pg_get_indexdef_string(Oid indexrelid)
 {
-       return pg_get_indexdef_worker(indexrelid, 0, 0);
+       return pg_get_indexdef_worker(indexrelid, 0, true, 0);
 }
 
 static char *
-pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
+pg_get_indexdef_worker(Oid indexrelid, int colno, bool showTblSpc,
+                                          int prettyFlags)
 {
        HeapTuple       ht_idx;
        HeapTuple       ht_idxrel;
@@ -784,6 +793,19 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
        {
                appendStringInfoChar(&buf, ')');
 
+               /*
+                * If it's in a nondefault tablespace, say so, but only if requested
+                */
+               if (showTblSpc)
+               {
+                       Oid                     tblspc;
+
+                       tblspc = get_rel_tablespace(indexrelid);
+                       if (OidIsValid(tblspc))
+                               appendStringInfo(&buf, " TABLESPACE %s",
+                                                                quote_identifier(get_tablespace_name(tblspc)));
+               }
+
                /*
                 * If it's a partial index, decompile and append the predicate
                 */
@@ -1012,6 +1034,7 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                        {
                                Datum           val;
                                bool            isnull;
+                               Oid                     indexId;
 
                                /* Start off the constraint definition */
                                if (conForm->contype == CONSTRAINT_PRIMARY)
@@ -1029,6 +1052,20 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                                decompile_column_index_array(val, conForm->conrelid, &buf);
 
                                appendStringInfo(&buf, ")");
+
+                               indexId = get_constraint_index(constraintId);
+
+                               /* XXX why do we only print this bit if fullCommand? */
+                               if (fullCommand && OidIsValid(indexId))
+                               {
+                                       Oid                     tblspc;
+
+                                       tblspc = get_rel_tablespace(indexId);
+                                       if (OidIsValid(tblspc))
+                                               appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
+                                                                                quote_identifier(get_tablespace_name(tblspc)));
+                               }
+
                                break;
                        }
                case CONSTRAINT_CHECK:
@@ -1339,7 +1376,69 @@ pg_get_serial_sequence(PG_FUNCTION_ARGS)
 }
 
 
-/* ----------
+/*
+ * get_constraint_index
+ *             Given the OID of a unique or primary-key constraint, return the
+ *             OID of the underlying unique index.
+ *
+ * Return InvalidOid if the index couldn't be found; this suggests the
+ * given OID is bogus, but we leave it to caller to decide what to do.
+ */
+static Oid
+get_constraint_index(Oid constraintId)
+{
+       Oid                     indexId = InvalidOid;
+       Relation        depRel;
+       ScanKeyData key[3];
+       SysScanDesc scan;
+       HeapTuple       tup;
+
+       /* Search the dependency table for the dependent index */
+       depRel = heap_open(DependRelationId, AccessShareLock);
+
+       ScanKeyInit(&key[0],
+                               Anum_pg_depend_refclassid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(ConstraintRelationId));
+       ScanKeyInit(&key[1],
+                               Anum_pg_depend_refobjid,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(constraintId));
+       ScanKeyInit(&key[2],
+                               Anum_pg_depend_refobjsubid,
+                               BTEqualStrategyNumber, F_INT4EQ,
+                               Int32GetDatum(0));
+
+       scan = systable_beginscan(depRel, DependReferenceIndexId, true,
+                                                         SnapshotNow, 3, key);
+
+       while (HeapTupleIsValid(tup = systable_getnext(scan)))
+       {
+               Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
+
+               /*
+                * We assume any internal dependency of an index on the constraint
+                * must be what we are looking for.  (The relkind test is just
+                * paranoia; there shouldn't be any such dependencies otherwise.)
+                */
+               if (deprec->classid == RelationRelationId &&
+                       deprec->objsubid == 0 &&
+                       deprec->deptype == DEPENDENCY_INTERNAL &&
+                       get_rel_relkind(deprec->objid) == RELKIND_INDEX)
+               {
+                       indexId = deprec->objid;
+                       break;
+               }
+       }
+
+       systable_endscan(scan);
+       heap_close(depRel, AccessShareLock);
+
+       return indexId;
+}
+
+
+/*
  * deparse_expression                  - General utility for deparsing expressions
  *
  * calls deparse_expression_pretty with all prettyPrinting disabled
index 309ce0a39456b8e5e3b475f7a2fb6fa0b3c6116c..3df1fc222a14a204d1009a545bdb04b4577b40f9 100644 (file)
@@ -1068,6 +1068,35 @@ get_rel_relkind(Oid relid)
                return '\0';
 }
 
+/*
+ * get_rel_tablespace
+ *
+ *             Returns the pg_tablespace OID associated with a given relation.
+ *
+ * Note: InvalidOid might mean either that we couldn't find the relation,
+ * or that it is in the database's default tablespace.
+ */
+Oid
+get_rel_tablespace(Oid relid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(RELOID,
+                                               ObjectIdGetDatum(relid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
+               Oid                     result;
+
+               result = reltup->reltablespace;
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return InvalidOid;
+}
+
 
 /*                             ---------- TYPE CACHE ----------                                                 */
 
index 5320d2ad06dfadcbcb68f6bfcc9506ce9f6c4563..5da3f3a37498d5b860c720eca7c7a3a0893c92cb 100644 (file)
@@ -66,6 +66,7 @@ extern char *get_rel_name(Oid relid);
 extern Oid     get_rel_namespace(Oid relid);
 extern Oid     get_rel_type_id(Oid relid);
 extern char get_rel_relkind(Oid relid);
+extern Oid     get_rel_tablespace(Oid relid);
 extern bool get_typisdefined(Oid typid);
 extern int16 get_typlen(Oid typid);
 extern bool get_typbyval(Oid typid);