]> 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:40 +0000 (15:55 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 13 Oct 2007 15:55:40 +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 4870209d46bfd57fe6c6a36186a35959be456d17..0aafb3b139e5af99fae4f7b8ce9e428339c3a797 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.263 2007/07/17 05:02:02 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.264 2007/10/13 15:55:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,6 +28,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_trigger.h"
 #include "commands/defrem.h"
+#include "commands/tablespace.h"
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "nodes/makefuncs.h"
@@ -126,12 +127,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,
@@ -577,6 +579,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
@@ -584,7 +590,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
@@ -596,18 +603,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;
@@ -798,8 +807,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
@@ -1014,6 +1032,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)
@@ -1032,15 +1051,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;
@@ -1356,7 +1384,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 d86a70521e3c2674b82c78b1fe0274805ba38581..d82e7debf5302bf527f4cb7f0e333015d3d18ecf 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.152 2007/05/11 17:57:12 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.153 2007/10/13 15:55:40 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -1611,6 +1611,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 0a326cb9ba9f24401ab417d21ed4b1f921254209..b8297bd49cf87cccf612b5f67d74d5f5dc08ef0f 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.119 2007/06/06 23:00:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.120 2007/10/13 15:55:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,6 +86,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);