]> granicus.if.org Git - postgresql/commitdiff
Fix ALTER COLUMN TYPE to preserve the tablespace and reloptions of indexes
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 13 Oct 2007 15:55:49 +0000 (15:55 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 13 Oct 2007 15:55:49 +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 7b57c5bb11cb8aeb1184b14ca0c89b5831c936b8..b7c3d50767d962749f78c4bab0432b79fe34dfc1 100644 (file)
@@ -2,7 +2,7 @@
  * ruleutils.c - Functions to convert stored expressions/querytrees
  *                             back to source text
  *
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.235.2.2 2007/01/30 02:32:05 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.235.2.3 2007/10/13 15:55:49 tgl Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -19,6 +19,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 "nodes/makefuncs.h"
@@ -119,12 +120,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,
@@ -567,6 +569,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
@@ -574,7 +580,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
@@ -586,18 +593,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;
@@ -766,8 +775,17 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
                }
 
                /*
-                * XXX we don't include the tablespace ... this is for pg_dump
+                * 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
@@ -997,6 +1015,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)
@@ -1015,15 +1034,24 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
 
                                appendStringInfo(&buf, ")");
 
-                               if (fullCommand && OidIsValid(conForm->conrelid))
+                               indexId = get_constraint_index(constraintId);
+
+                               /* XXX why do we only print these bits if fullCommand? */
+                               if (fullCommand && OidIsValid(indexId))
                                {
-                                       char       *options = flatten_reloptions(conForm->conrelid);
+                                       char       *options = flatten_reloptions(indexId);
+                                       Oid                     tblspc;
 
                                        if (options)
                                        {
                                                appendStringInfo(&buf, " WITH (%s)", options);
                                                pfree(options);
                                        }
+
+                                       tblspc = get_rel_tablespace(indexId);
+                                       if (OidIsValid(tblspc))
+                                               appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
+                                                                                quote_identifier(get_tablespace_name(tblspc)));
                                }
 
                                break;
@@ -1340,7 +1368,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 99dd84a9fa7c9cf5fa4be8ef1ecff5714b5a55ce..350d9661f56081b1d8633a03100bfe2d53497d31 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.138.2.1 2007/03/19 16:30:40 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.138.2.2 2007/10/13 15:55:49 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -1210,6 +1210,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 69eb31bcc559d7fda7a3ff530f439853d9e1a637..26dc09b8ada3d295fe4ad166f2b1945b886bf981 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.107 2006/10/04 00:30:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.107.2.1 2007/10/13 15:55:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,6 +72,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);