mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Fix ALTER COLUMN TYPE to preserve the tablespace and reloptions of indexes
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.
This commit is contained in:
parent
ef3ff3eee4
commit
5b8328b936
@ -2,7 +2,7 @@
|
|||||||
* ruleutils.c - Functions to convert stored expressions/querytrees
|
* ruleutils.c - Functions to convert stored expressions/querytrees
|
||||||
* back to source text
|
* 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"
|
#include "postgres.h"
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#include "catalog/pg_opclass.h"
|
#include "catalog/pg_opclass.h"
|
||||||
#include "catalog/pg_operator.h"
|
#include "catalog/pg_operator.h"
|
||||||
#include "catalog/pg_trigger.h"
|
#include "catalog/pg_trigger.h"
|
||||||
|
#include "commands/tablespace.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "nodes/makefuncs.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,
|
static void decompile_column_index_array(Datum column_index_array, Oid relId,
|
||||||
StringInfo buf);
|
StringInfo buf);
|
||||||
static char *pg_get_ruledef_worker(Oid ruleoid, int prettyFlags);
|
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);
|
int prettyFlags);
|
||||||
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
|
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
|
||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
|
static Oid get_constraint_index(Oid constraintId);
|
||||||
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
||||||
int prettyFlags);
|
int prettyFlags);
|
||||||
static void make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
|
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.
|
* 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 want a complete index definition.
|
||||||
* if colno > 0, we only want the Nth index key's variable or expression.
|
* 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
|
Datum
|
||||||
@ -574,7 +580,8 @@ pg_get_indexdef(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Oid indexrelid = PG_GETARG_OID(0);
|
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
|
Datum
|
||||||
@ -586,18 +593,20 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
|
|||||||
int prettyFlags;
|
int prettyFlags;
|
||||||
|
|
||||||
prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : 0;
|
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 */
|
/* Internal version that returns a palloc'd C string */
|
||||||
char *
|
char *
|
||||||
pg_get_indexdef_string(Oid indexrelid)
|
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 *
|
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_idx;
|
||||||
HeapTuple ht_idxrel;
|
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
|
* 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;
|
Datum val;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
Oid indexId;
|
||||||
|
|
||||||
/* Start off the constraint definition */
|
/* Start off the constraint definition */
|
||||||
if (conForm->contype == CONSTRAINT_PRIMARY)
|
if (conForm->contype == CONSTRAINT_PRIMARY)
|
||||||
@ -1015,15 +1034,24 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
|
|||||||
|
|
||||||
appendStringInfo(&buf, ")");
|
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)
|
if (options)
|
||||||
{
|
{
|
||||||
appendStringInfo(&buf, " WITH (%s)", options);
|
appendStringInfo(&buf, " WITH (%s)", options);
|
||||||
pfree(options);
|
pfree(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tblspc = get_rel_tablespace(indexId);
|
||||||
|
if (OidIsValid(tblspc))
|
||||||
|
appendStringInfo(&buf, " USING INDEX TABLESPACE %s",
|
||||||
|
quote_identifier(get_tablespace_name(tblspc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
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
|
* deparse_expression - General utility for deparsing expressions
|
||||||
*
|
*
|
||||||
* calls deparse_expression_pretty with all prettyPrinting disabled
|
* calls deparse_expression_pretty with all prettyPrinting disabled
|
||||||
|
31
src/backend/utils/cache/lsyscache.c
vendored
31
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Eventually, the index information should go through here, too.
|
* Eventually, the index information should go through here, too.
|
||||||
@ -1210,6 +1210,35 @@ get_rel_relkind(Oid relid)
|
|||||||
return '\0';
|
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 ---------- */
|
/* ---------- TYPE CACHE ---------- */
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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_namespace(Oid relid);
|
||||||
extern Oid get_rel_type_id(Oid relid);
|
extern Oid get_rel_type_id(Oid relid);
|
||||||
extern char get_rel_relkind(Oid relid);
|
extern char get_rel_relkind(Oid relid);
|
||||||
|
extern Oid get_rel_tablespace(Oid relid);
|
||||||
extern bool get_typisdefined(Oid typid);
|
extern bool get_typisdefined(Oid typid);
|
||||||
extern int16 get_typlen(Oid typid);
|
extern int16 get_typlen(Oid typid);
|
||||||
extern bool get_typbyval(Oid typid);
|
extern bool get_typbyval(Oid typid);
|
||||||
|
Loading…
Reference in New Issue
Block a user