mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
Apply fixes for problems with dropped columns whose types have also been
dropped. Add regression test, too.
This commit is contained in:
parent
016e059fcf
commit
3ffaf20461
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232.2.1 2002/12/16 18:39:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232.2.2 2003/05/12 00:17:33 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -75,7 +75,7 @@ static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
|
|||||||
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
|
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
|
||||||
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
|
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
|
||||||
static void SetRelationNumChecks(Relation rel, int numchecks);
|
static void SetRelationNumChecks(Relation rel, int numchecks);
|
||||||
static void RemoveStatistics(Relation rel);
|
static void RemoveStatistics(Relation rel, AttrNumber attnum);
|
||||||
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
@ -911,8 +911,9 @@ DeleteAttributeTuples(Oid relid)
|
|||||||
* RemoveAttributeById
|
* RemoveAttributeById
|
||||||
*
|
*
|
||||||
* This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
|
* This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
|
||||||
* deleted in pg_attribute. (Everything else needed, such as getting rid
|
* deleted in pg_attribute. We also remove pg_statistic entries for it.
|
||||||
* of any pg_attrdef entry, is handled by dependency.c.)
|
* (Everything else needed, such as getting rid of any pg_attrdef entry,
|
||||||
|
* is handled by dependency.c.)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RemoveAttributeById(Oid relid, AttrNumber attnum)
|
RemoveAttributeById(Oid relid, AttrNumber attnum)
|
||||||
@ -946,6 +947,16 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|||||||
/* Mark the attribute as dropped */
|
/* Mark the attribute as dropped */
|
||||||
attStruct->attisdropped = true;
|
attStruct->attisdropped = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the type OID to invalid. A dropped attribute's type link cannot
|
||||||
|
* be relied on (once the attribute is dropped, the type might be too).
|
||||||
|
* Fortunately we do not need the type row --- the only really essential
|
||||||
|
* information is the type's typlen and typalign, which are preserved in
|
||||||
|
* the attribute's attlen and attalign. We set atttypid to zero here
|
||||||
|
* as a means of catching code that incorrectly expects it to be valid.
|
||||||
|
*/
|
||||||
|
attStruct->atttypid = InvalidOid;
|
||||||
|
|
||||||
/* Remove any NOT NULL constraint the column may have */
|
/* Remove any NOT NULL constraint the column may have */
|
||||||
attStruct->attnotnull = false;
|
attStruct->attnotnull = false;
|
||||||
|
|
||||||
@ -969,6 +980,8 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|||||||
|
|
||||||
heap_close(attr_rel, RowExclusiveLock);
|
heap_close(attr_rel, RowExclusiveLock);
|
||||||
|
|
||||||
|
RemoveStatistics(rel, attnum);
|
||||||
|
|
||||||
relation_close(rel, NoLock);
|
relation_close(rel, NoLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,7 +1156,7 @@ heap_drop_with_catalog(Oid rid)
|
|||||||
/*
|
/*
|
||||||
* delete statistics
|
* delete statistics
|
||||||
*/
|
*/
|
||||||
RemoveStatistics(rel);
|
RemoveStatistics(rel, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* delete attribute tuples
|
* delete attribute tuples
|
||||||
@ -1817,27 +1830,45 @@ RemoveRelConstraints(Relation rel, const char *constrName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RemoveStatistics --- remove entries in pg_statistic for a rel or column
|
||||||
|
*
|
||||||
|
* If attnum is zero, remove all entries for rel; else remove only the one
|
||||||
|
* for that column.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
RemoveStatistics(Relation rel)
|
RemoveStatistics(Relation rel, AttrNumber attnum)
|
||||||
{
|
{
|
||||||
Relation pgstatistic;
|
Relation pgstatistic;
|
||||||
SysScanDesc scan;
|
SysScanDesc scan;
|
||||||
ScanKeyData key;
|
ScanKeyData key[2];
|
||||||
|
int nkeys;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
|
|
||||||
pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);
|
pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
ScanKeyEntryInitialize(&key, 0x0,
|
ScanKeyEntryInitialize(&key[0], 0x0,
|
||||||
Anum_pg_statistic_starelid, F_OIDEQ,
|
Anum_pg_statistic_starelid, F_OIDEQ,
|
||||||
ObjectIdGetDatum(RelationGetRelid(rel)));
|
ObjectIdGetDatum(RelationGetRelid(rel)));
|
||||||
|
|
||||||
|
if (attnum == 0)
|
||||||
|
nkeys = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScanKeyEntryInitialize(&key[1], 0x0,
|
||||||
|
Anum_pg_statistic_staattnum, F_INT2EQ,
|
||||||
|
Int16GetDatum(attnum));
|
||||||
|
nkeys = 2;
|
||||||
|
}
|
||||||
|
|
||||||
scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndex, true,
|
scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndex, true,
|
||||||
SnapshotNow, 1, &key);
|
SnapshotNow, nkeys, key);
|
||||||
|
|
||||||
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
while (HeapTupleIsValid(tuple = systable_getnext(scan)))
|
||||||
simple_heap_delete(pgstatistic, &tuple->t_self);
|
simple_heap_delete(pgstatistic, &tuple->t_self);
|
||||||
|
|
||||||
systable_endscan(scan);
|
systable_endscan(scan);
|
||||||
|
|
||||||
heap_close(pgstatistic, RowExclusiveLock);
|
heap_close(pgstatistic, RowExclusiveLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57 2002/09/18 21:35:21 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57.2.1 2003/05/12 00:17:34 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -171,6 +171,15 @@ expand_targetlist(List *tlist, int command_type,
|
|||||||
* the attribute, so that it gets copied to the new tuple. But
|
* the attribute, so that it gets copied to the new tuple. But
|
||||||
* generate a NULL for dropped columns (we want to drop any
|
* generate a NULL for dropped columns (we want to drop any
|
||||||
* old values).
|
* old values).
|
||||||
|
*
|
||||||
|
* When generating a NULL constant for a dropped column, we label
|
||||||
|
* it INT4 (any other guaranteed-to-exist datatype would do as
|
||||||
|
* well). We can't label it with the dropped column's datatype
|
||||||
|
* since that might not exist anymore. It does not really
|
||||||
|
* matter what we claim the type is, since NULL is NULL --- its
|
||||||
|
* representation is datatype-independent. This could perhaps
|
||||||
|
* confuse code comparing the finished plan to the target
|
||||||
|
* relation, however.
|
||||||
*/
|
*/
|
||||||
Oid atttype = att_tup->atttypid;
|
Oid atttype = att_tup->atttypid;
|
||||||
int32 atttypmod = att_tup->atttypmod;
|
int32 atttypmod = att_tup->atttypmod;
|
||||||
@ -179,6 +188,8 @@ expand_targetlist(List *tlist, int command_type,
|
|||||||
switch (command_type)
|
switch (command_type)
|
||||||
{
|
{
|
||||||
case CMD_INSERT:
|
case CMD_INSERT:
|
||||||
|
if (!att_tup->attisdropped)
|
||||||
|
{
|
||||||
new_expr = (Node *) makeConst(atttype,
|
new_expr = (Node *) makeConst(atttype,
|
||||||
att_tup->attlen,
|
att_tup->attlen,
|
||||||
(Datum) 0,
|
(Datum) 0,
|
||||||
@ -186,27 +197,48 @@ expand_targetlist(List *tlist, int command_type,
|
|||||||
att_tup->attbyval,
|
att_tup->attbyval,
|
||||||
false, /* not a set */
|
false, /* not a set */
|
||||||
false);
|
false);
|
||||||
if (!att_tup->attisdropped)
|
|
||||||
new_expr = coerce_type_constraints(new_expr,
|
new_expr = coerce_type_constraints(new_expr,
|
||||||
atttype,
|
atttype,
|
||||||
COERCE_IMPLICIT_CAST);
|
COERCE_IMPLICIT_CAST);
|
||||||
break;
|
}
|
||||||
case CMD_UPDATE:
|
else
|
||||||
/* Insert NULLs for dropped columns */
|
{
|
||||||
if (att_tup->attisdropped)
|
/* Insert NULL for dropped column */
|
||||||
new_expr = (Node *) makeConst(atttype,
|
new_expr = (Node *) makeConst(INT4OID,
|
||||||
att_tup->attlen,
|
sizeof(int32),
|
||||||
(Datum) 0,
|
(Datum) 0,
|
||||||
true, /* isnull */
|
true, /* isnull */
|
||||||
att_tup->attbyval,
|
true, /* byval */
|
||||||
false, /* not a set */
|
false, /* not a set */
|
||||||
false);
|
false);
|
||||||
else
|
/* label resdom with INT4, too */
|
||||||
|
atttype = INT4OID;
|
||||||
|
atttypmod = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CMD_UPDATE:
|
||||||
|
if (!att_tup->attisdropped)
|
||||||
|
{
|
||||||
new_expr = (Node *) makeVar(result_relation,
|
new_expr = (Node *) makeVar(result_relation,
|
||||||
attrno,
|
attrno,
|
||||||
atttype,
|
atttype,
|
||||||
atttypmod,
|
atttypmod,
|
||||||
0);
|
0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Insert NULL for dropped column */
|
||||||
|
new_expr = (Node *) makeConst(INT4OID,
|
||||||
|
sizeof(int32),
|
||||||
|
(Datum) 0,
|
||||||
|
true, /* isnull */
|
||||||
|
true, /* byval */
|
||||||
|
false, /* not a set */
|
||||||
|
false);
|
||||||
|
/* label resdom with INT4, too */
|
||||||
|
atttype = INT4OID;
|
||||||
|
atttypmod = -1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
elog(ERROR, "expand_targetlist: unexpected command_type");
|
elog(ERROR, "expand_targetlist: unexpected command_type");
|
||||||
|
@ -1166,3 +1166,44 @@ order by relname, attnum;
|
|||||||
drop table p1, p2 cascade;
|
drop table p1, p2 cascade;
|
||||||
NOTICE: Drop cascades to table c1
|
NOTICE: Drop cascades to table c1
|
||||||
NOTICE: Drop cascades to table gc1
|
NOTICE: Drop cascades to table gc1
|
||||||
|
-- test that operations with a dropped column do not try to reference
|
||||||
|
-- its datatype
|
||||||
|
create domain mytype as text;
|
||||||
|
create temp table foo (f1 text, f2 mytype, f3 text);
|
||||||
|
insert into foo values('aa','bb','cc');
|
||||||
|
select * from foo;
|
||||||
|
f1 | f2 | f3
|
||||||
|
----+----+----
|
||||||
|
aa | bb | cc
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
drop domain mytype cascade;
|
||||||
|
NOTICE: Drop cascades to table foo column f2
|
||||||
|
select * from foo;
|
||||||
|
f1 | f3
|
||||||
|
----+----
|
||||||
|
aa | cc
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
insert into foo values('qq','rr');
|
||||||
|
select * from foo;
|
||||||
|
f1 | f3
|
||||||
|
----+----
|
||||||
|
aa | cc
|
||||||
|
qq | rr
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
update foo set f3 = 'zz';
|
||||||
|
select * from foo;
|
||||||
|
f1 | f3
|
||||||
|
----+----
|
||||||
|
aa | zz
|
||||||
|
qq | zz
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
select f3,max(f1) from foo group by f3;
|
||||||
|
f3 | max
|
||||||
|
----+-----
|
||||||
|
zz | qq
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -845,3 +845,21 @@ where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
|
|||||||
order by relname, attnum;
|
order by relname, attnum;
|
||||||
|
|
||||||
drop table p1, p2 cascade;
|
drop table p1, p2 cascade;
|
||||||
|
|
||||||
|
-- test that operations with a dropped column do not try to reference
|
||||||
|
-- its datatype
|
||||||
|
|
||||||
|
create domain mytype as text;
|
||||||
|
create temp table foo (f1 text, f2 mytype, f3 text);
|
||||||
|
|
||||||
|
insert into foo values('aa','bb','cc');
|
||||||
|
select * from foo;
|
||||||
|
|
||||||
|
drop domain mytype cascade;
|
||||||
|
|
||||||
|
select * from foo;
|
||||||
|
insert into foo values('qq','rr');
|
||||||
|
select * from foo;
|
||||||
|
update foo set f3 = 'zz';
|
||||||
|
select * from foo;
|
||||||
|
select f3,max(f1) from foo group by f3;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user