Commit c328b6dd authored by Tom Lane's avatar Tom Lane

Replace pg_attribute.attisinherited with attislocal and attinhcount

columns, to allow more correct behavior in multiple-inheritance cases.
Patch by Alvaro Herrera, review by Tom Lane.
parent 634e440b
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.60 2002/09/18 21:35:20 tgl Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.61 2002/09/22 19:42:50 tgl Exp $
--> -->
<chapter id="catalogs"> <chapter id="catalogs">
...@@ -822,12 +822,22 @@ ...@@ -822,12 +822,22 @@
</row> </row>
<row> <row>
<entry>attisinherited</entry> <entry>attislocal</entry>
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
<entry></entry> <entry></entry>
<entry> <entry>
This column is inherited from some other relation. An inherited This column is defined locally in the relation. Note that a column may
column cannot be dropped nor renamed. be locally defined and inherited simultaneously.
</entry>
</row>
<row>
<entry>attinhcount</entry>
<entry><type>int4</type></entry>
<entry></entry>
<entry>
The number of direct ancestors this column has. A column with a
nonzero number of ancestors cannot be dropped nor renamed.
</entry> </entry>
</row> </row>
...@@ -1213,8 +1223,8 @@ ...@@ -1213,8 +1223,8 @@
<entry></entry> <entry></entry>
<entry> <entry>
'c' = check constraint, 'c' = check constraint,
'f' = foreign key constraint, 'f' = foreign key constraint,
'p' = primary key constraint, 'p' = primary key constraint,
'u' = unique constraint 'u' = unique constraint
</entry> </entry>
</row> </row>
...@@ -3316,7 +3326,7 @@ ...@@ -3316,7 +3326,7 @@
when storing a value of this type. It applies to storage on when storing a value of this type. It applies to storage on
disk as well as most representations of the value inside disk as well as most representations of the value inside
<productname>PostgreSQL</>. <productname>PostgreSQL</>.
When multiple values are stored consecutively, such When multiple values are stored consecutively, such
as in the representation of a complete row on disk, padding is as in the representation of a complete row on disk, padding is
inserted before a datum of this type so that it begins on the inserted before a datum of this type so that it begins on the
specified boundary. The alignment reference is the beginning specified boundary. The alignment reference is the beginning
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.89 2002/09/04 20:31:09 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.90 2002/09/22 19:42:50 tgl Exp $
* *
* NOTES * NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be * some of the executor utility code such as "ExecTypeFromTL" should be
...@@ -271,7 +271,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) ...@@ -271,7 +271,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
return false; return false;
if (attr1->attisdropped != attr2->attisdropped) if (attr1->attisdropped != attr2->attisdropped)
return false; return false;
if (attr1->attisinherited != attr2->attisinherited) if (attr1->attislocal != attr2->attislocal)
return false;
if (attr1->attinhcount != attr2->attinhcount)
return false; return false;
} }
if (tupdesc1->constr != NULL) if (tupdesc1->constr != NULL)
...@@ -396,7 +398,8 @@ TupleDescInitEntry(TupleDesc desc, ...@@ -396,7 +398,8 @@ TupleDescInitEntry(TupleDesc desc,
att->attnotnull = false; att->attnotnull = false;
att->atthasdef = false; att->atthasdef = false;
att->attisdropped = false; att->attisdropped = false;
att->attisinherited = false; att->attislocal = true;
att->attinhcount = 0;
tuple = SearchSysCache(TYPEOID, tuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(oidtypeid), ObjectIdGetDatum(oidtypeid),
...@@ -543,7 +546,8 @@ BuildDescForRelation(List *schema) ...@@ -543,7 +546,8 @@ BuildDescForRelation(List *schema)
desc->attrs[attnum - 1]->atthasdef = true; desc->attrs[attnum - 1]->atthasdef = true;
} }
desc->attrs[attnum - 1]->attisinherited = entry->is_inherited; desc->attrs[attnum - 1]->attislocal = entry->is_local;
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
} }
if (constr->has_not_null || ndef > 0) if (constr->has_not_null || ndef > 0)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,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/bootstrap/bootstrap.c,v 1.141 2002/09/04 20:31:13 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.142 2002/09/22 19:42:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -587,7 +587,7 @@ DefineAttr(char *name, char *type, int attnum) ...@@ -587,7 +587,7 @@ DefineAttr(char *name, char *type, int attnum)
namestrcpy(&attrtypes[attnum]->attname, name); namestrcpy(&attrtypes[attnum]->attname, name);
elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type); elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type);
attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ attrtypes[attnum]->attnum = attnum + 1; /* fillatt */
typeoid = gettype(type); typeoid = gettype(type);
...@@ -640,6 +640,7 @@ DefineAttr(char *name, char *type, int attnum) ...@@ -640,6 +640,7 @@ DefineAttr(char *name, char *type, int attnum)
} }
attrtypes[attnum]->attcacheoff = -1; attrtypes[attnum]->attcacheoff = -1;
attrtypes[attnum]->atttypmod = -1; attrtypes[attnum]->atttypmod = -1;
attrtypes[attnum]->attislocal = true;
/* /*
* Mark as "not null" if type is fixed-width and prior columns are * Mark as "not null" if type is fixed-width and prior columns are
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.230 2002/09/22 00:37:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.231 2002/09/22 19:42:50 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -97,37 +97,37 @@ static void RemoveStatistics(Relation rel); ...@@ -97,37 +97,37 @@ static void RemoveStatistics(Relation rel);
static FormData_pg_attribute a1 = { static FormData_pg_attribute a1 = {
0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), 0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData),
SelfItemPointerAttributeNumber, 0, -1, -1, SelfItemPointerAttributeNumber, 0, -1, -1,
false, 'p', false, 'i', true, false, false false, 'p', false, 'i', true, false, false, true, 0
}; };
static FormData_pg_attribute a2 = { static FormData_pg_attribute a2 = {
0, {"oid"}, OIDOID, 0, sizeof(Oid), 0, {"oid"}, OIDOID, 0, sizeof(Oid),
ObjectIdAttributeNumber, 0, -1, -1, ObjectIdAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
static FormData_pg_attribute a3 = { static FormData_pg_attribute a3 = {
0, {"xmin"}, XIDOID, 0, sizeof(TransactionId), 0, {"xmin"}, XIDOID, 0, sizeof(TransactionId),
MinTransactionIdAttributeNumber, 0, -1, -1, MinTransactionIdAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
static FormData_pg_attribute a4 = { static FormData_pg_attribute a4 = {
0, {"cmin"}, CIDOID, 0, sizeof(CommandId), 0, {"cmin"}, CIDOID, 0, sizeof(CommandId),
MinCommandIdAttributeNumber, 0, -1, -1, MinCommandIdAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
static FormData_pg_attribute a5 = { static FormData_pg_attribute a5 = {
0, {"xmax"}, XIDOID, 0, sizeof(TransactionId), 0, {"xmax"}, XIDOID, 0, sizeof(TransactionId),
MaxTransactionIdAttributeNumber, 0, -1, -1, MaxTransactionIdAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
static FormData_pg_attribute a6 = { static FormData_pg_attribute a6 = {
0, {"cmax"}, CIDOID, 0, sizeof(CommandId), 0, {"cmax"}, CIDOID, 0, sizeof(CommandId),
MaxCommandIdAttributeNumber, 0, -1, -1, MaxCommandIdAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
/* /*
...@@ -139,7 +139,7 @@ static FormData_pg_attribute a6 = { ...@@ -139,7 +139,7 @@ static FormData_pg_attribute a6 = {
static FormData_pg_attribute a7 = { static FormData_pg_attribute a7 = {
0, {"tableoid"}, OIDOID, 0, sizeof(Oid), 0, {"tableoid"}, OIDOID, 0, sizeof(Oid),
TableOidAttributeNumber, 0, -1, -1, TableOidAttributeNumber, 0, -1, -1,
true, 'p', false, 'i', true, false, false true, 'p', false, 'i', true, false, false, true, 0
}; };
static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.197 2002/09/22 00:37:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.198 2002/09/22 19:42:50 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -165,10 +165,11 @@ BuildFuncTupleDesc(Oid funcOid, ...@@ -165,10 +165,11 @@ BuildFuncTupleDesc(Oid funcOid,
funcTupDesc->attrs[0]->atttypid = keyType; funcTupDesc->attrs[0]->atttypid = keyType;
funcTupDesc->attrs[0]->attlen = typeTup->typlen; funcTupDesc->attrs[0]->attlen = typeTup->typlen;
funcTupDesc->attrs[0]->attbyval = typeTup->typbyval; funcTupDesc->attrs[0]->attbyval = typeTup->typbyval;
funcTupDesc->attrs[0]->attcacheoff = -1;
funcTupDesc->attrs[0]->atttypmod = -1;
funcTupDesc->attrs[0]->attstorage = typeTup->typstorage; funcTupDesc->attrs[0]->attstorage = typeTup->typstorage;
funcTupDesc->attrs[0]->attalign = typeTup->typalign; funcTupDesc->attrs[0]->attalign = typeTup->typalign;
funcTupDesc->attrs[0]->attcacheoff = -1;
funcTupDesc->attrs[0]->atttypmod = -1;
funcTupDesc->attrs[0]->attislocal = true;
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
...@@ -259,7 +260,8 @@ ConstructTupleDescriptor(Relation heapRelation, ...@@ -259,7 +260,8 @@ ConstructTupleDescriptor(Relation heapRelation,
to->attcacheoff = -1; to->attcacheoff = -1;
to->attnotnull = false; to->attnotnull = false;
to->atthasdef = false; to->atthasdef = false;
to->attisinherited = false; to->attislocal = true;
to->attinhcount = 0;
/* /*
* We do not yet have the correct relation OID for the index, so * We do not yet have the correct relation OID for the index, so
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.87 2002/09/04 20:31:15 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.88 2002/09/22 19:42:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -127,7 +127,8 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -127,7 +127,8 @@ DefineSequence(CreateSeqStmt *seq)
coldef = makeNode(ColumnDef); coldef = makeNode(ColumnDef);
coldef->typename = typnam; coldef->typename = typnam;
coldef->is_inherited = false; coldef->inhcount = 0;
coldef->is_local = true;
coldef->is_not_null = true; coldef->is_not_null = true;
coldef->raw_default = NULL; coldef->raw_default = NULL;
coldef->cooked_default = NULL; coldef->cooked_default = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.42 2002/09/22 00:37:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.43 2002/09/22 19:42:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -609,6 +609,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, ...@@ -609,6 +609,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
attributeName, attributeName,
TypeNameToString(def->typename), TypeNameToString(def->typename),
format_type_be(attribute->atttypid)); format_type_be(attribute->atttypid));
def->inhcount++;
/* Merge of NOT NULL constraints = OR 'em together */ /* Merge of NOT NULL constraints = OR 'em together */
def->is_not_null |= attribute->attnotnull; def->is_not_null |= attribute->attnotnull;
/* Default and other constraints are handled below */ /* Default and other constraints are handled below */
...@@ -625,7 +626,8 @@ MergeAttributes(List *schema, List *supers, bool istemp, ...@@ -625,7 +626,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
typename->typeid = attribute->atttypid; typename->typeid = attribute->atttypid;
typename->typmod = attribute->atttypmod; typename->typmod = attribute->atttypmod;
def->typename = typename; def->typename = typename;
def->is_inherited = true; def->inhcount = 1;
def->is_local = false;
def->is_not_null = attribute->attnotnull; def->is_not_null = attribute->attnotnull;
def->raw_default = NULL; def->raw_default = NULL;
def->cooked_default = NULL; def->cooked_default = NULL;
...@@ -758,6 +760,8 @@ MergeAttributes(List *schema, List *supers, bool istemp, ...@@ -758,6 +760,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
attributeName, attributeName,
TypeNameToString(def->typename), TypeNameToString(def->typename),
TypeNameToString(newdef->typename)); TypeNameToString(newdef->typename));
/* Mark the column as locally defined */
def->is_local = true;
/* Merge of NOT NULL constraints = OR 'em together */ /* Merge of NOT NULL constraints = OR 'em together */
def->is_not_null |= newdef->is_not_null; def->is_not_null |= newdef->is_not_null;
/* If new def has a default, override previous default */ /* If new def has a default, override previous default */
...@@ -1155,7 +1159,7 @@ renameatt(Oid myrelid, ...@@ -1155,7 +1159,7 @@ renameatt(Oid myrelid,
* if the attribute is inherited, forbid the renaming, unless we are * if the attribute is inherited, forbid the renaming, unless we are
* already inside a recursive rename. * already inside a recursive rename.
*/ */
if (attform->attisinherited && !recursing) if (attform->attinhcount > 0 && !recursing)
elog(ERROR, "renameatt: inherited attribute \"%s\" may not be renamed", elog(ERROR, "renameatt: inherited attribute \"%s\" may not be renamed",
oldattname); oldattname);
...@@ -1628,7 +1632,8 @@ AlterTableAddColumn(Oid myrelid, ...@@ -1628,7 +1632,8 @@ AlterTableAddColumn(Oid myrelid,
*children; *children;
ColumnDef *colDefChild = copyObject(colDef); ColumnDef *colDefChild = copyObject(colDef);
colDefChild->is_inherited = true; colDefChild->inhcount = 1;
colDefChild->is_local = false;
/* this routine is actually in the planner */ /* this routine is actually in the planner */
children = find_all_inheritors(myrelid); children = find_all_inheritors(myrelid);
...@@ -1742,7 +1747,8 @@ AlterTableAddColumn(Oid myrelid, ...@@ -1742,7 +1747,8 @@ AlterTableAddColumn(Oid myrelid,
attribute->atthasdef = (colDef->raw_default != NULL || attribute->atthasdef = (colDef->raw_default != NULL ||
colDef->cooked_default != NULL); colDef->cooked_default != NULL);
attribute->attisdropped = false; attribute->attisdropped = false;
attribute->attisinherited = colDef->is_inherited; attribute->attislocal = colDef->is_local;
attribute->attinhcount = colDef->inhcount;
ReleaseSysCache(typeTuple); ReleaseSysCache(typeTuple);
...@@ -2373,13 +2379,14 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing, ...@@ -2373,13 +2379,14 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
RelationGetRelationName(rel)); RelationGetRelationName(rel));
/* Don't drop inherited columns */ /* Don't drop inherited columns */
if (tupleDesc->attrs[attnum - 1]->attisinherited && !recursing) if (tupleDesc->attrs[attnum - 1]->attinhcount > 0 && !recursing)
elog(ERROR, "ALTER TABLE: Cannot drop inherited column \"%s\"", elog(ERROR, "ALTER TABLE: Cannot drop inherited column \"%s\"",
colName); colName);
/* /*
* If we are asked to drop ONLY in this table (no recursion), we need * If we are asked to drop ONLY in this table (no recursion), we need
* to mark the inheritors' attribute as non-inherited. * to mark the inheritors' attribute as locally defined rather than
* inherited.
*/ */
if (!recurse && !recursing) if (!recurse && !recursing)
{ {
...@@ -2396,6 +2403,7 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing, ...@@ -2396,6 +2403,7 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
Oid childrelid = lfirsti(child); Oid childrelid = lfirsti(child);
Relation childrel; Relation childrel;
HeapTuple tuple; HeapTuple tuple;
Form_pg_attribute childatt;
childrel = heap_open(childrelid, AccessExclusiveLock); childrel = heap_open(childrelid, AccessExclusiveLock);
...@@ -2403,43 +2411,84 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing, ...@@ -2403,43 +2411,84 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "ALTER TABLE: relation %u has no column \"%s\"", elog(ERROR, "ALTER TABLE: relation %u has no column \"%s\"",
childrelid, colName); childrelid, colName);
childatt = (Form_pg_attribute) GETSTRUCT(tuple);
((Form_pg_attribute) GETSTRUCT(tuple))->attisinherited = false; if (childatt->attinhcount <= 0)
elog(ERROR, "ALTER TABLE: relation %u has non-inherited column \"%s\"",
childrelid, colName);
childatt->attinhcount--;
childatt->attislocal = true;
simple_heap_update(attr_rel, &tuple->t_self, tuple); simple_heap_update(attr_rel, &tuple->t_self, tuple);
/* keep the system catalog indexes current */ /* keep the system catalog indexes current */
CatalogUpdateIndexes(attr_rel, tuple); CatalogUpdateIndexes(attr_rel, tuple);
heap_freetuple(tuple);
heap_close(childrel, NoLock); heap_close(childrel, NoLock);
} }
heap_close(attr_rel, RowExclusiveLock); heap_close(attr_rel, RowExclusiveLock);
} }
/* /*
* Propagate to children if desired * Propagate to children if desired. Unlike most other ALTER routines,
* we have to do this one level of recursion at a time; we can't use
* find_all_inheritors to do it in one pass.
*/ */
if (recurse) if (recurse)
{ {
Relation attr_rel;
List *child, List *child,
*children; *children;
/* this routine is actually in the planner */ /* We only want direct inheritors in this case */
children = find_all_inheritors(myrelid); children = find_inheritance_children(myrelid);
/* attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process all of
* the relids in the list that it returns.
*/
foreach(child, children) foreach(child, children)
{ {
Oid childrelid = lfirsti(child); Oid childrelid = lfirsti(child);
Relation childrel;
HeapTuple tuple;
Form_pg_attribute childatt;
if (childrelid == myrelid) if (childrelid == myrelid)
continue; continue;
AlterTableDropColumn(childrelid, false, true, colName, behavior);
childrel = heap_open(childrelid, AccessExclusiveLock);
tuple = SearchSysCacheCopyAttName(childrelid, colName);
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
elog(ERROR, "ALTER TABLE: relation %u has no column \"%s\"",
childrelid, colName);
childatt = (Form_pg_attribute) GETSTRUCT(tuple);
if (childatt->attinhcount <= 0)
elog(ERROR, "ALTER TABLE: relation %u has non-inherited column \"%s\"",
childrelid, colName);
if (childatt->attinhcount == 1 && !childatt->attislocal)
{
/* Time to delete this child column, too */
AlterTableDropColumn(childrelid, true, true, colName, behavior);
}
else
{
/* Child column must survive my deletion */
childatt->attinhcount--;
simple_heap_update(attr_rel, &tuple->t_self, tuple);
/* keep the system catalog indexes current */
CatalogUpdateIndexes(attr_rel, tuple);
}
heap_freetuple(tuple);
heap_close(childrel, NoLock);
} }
heap_close(attr_rel, RowExclusiveLock);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.71 2002/09/04 20:31:17 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.72 2002/09/22 19:42:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -71,7 +71,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) ...@@ -71,7 +71,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
typename->typmod = res->restypmod; typename->typmod = res->restypmod;
def->typename = typename; def->typename = typename;
def->is_inherited = false; def->inhcount = 0;
def->is_local = true;
def->is_not_null = false; def->is_not_null = false;
def->raw_default = NULL; def->raw_default = NULL;
def->cooked_default = NULL; def->cooked_default = NULL;
......
...@@ -15,7 +15,7 @@ ...@@ -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/nodes/copyfuncs.c,v 1.212 2002/09/18 21:35:20 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.213 2002/09/22 19:42:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1732,7 +1732,8 @@ _copyColumnDef(ColumnDef *from) ...@@ -1732,7 +1732,8 @@ _copyColumnDef(ColumnDef *from)
if (from->colname) if (from->colname)
newnode->colname = pstrdup(from->colname); newnode->colname = pstrdup(from->colname);
Node_Copy(from, newnode, typename); Node_Copy(from, newnode, typename);
newnode->is_inherited = from->is_inherited; newnode->inhcount = from->inhcount;
newnode->is_local = from->is_local;
newnode->is_not_null = from->is_not_null; newnode->is_not_null = from->is_not_null;
Node_Copy(from, newnode, raw_default); Node_Copy(from, newnode, raw_default);
if (from->cooked_default) if (from->cooked_default)
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,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/nodes/equalfuncs.c,v 1.159 2002/09/18 21:35:20 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.160 2002/09/22 19:42:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1769,7 +1769,9 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b) ...@@ -1769,7 +1769,9 @@ _equalColumnDef(ColumnDef *a, ColumnDef *b)
return false; return false;
if (!equal(a->typename, b->typename)) if (!equal(a->typename, b->typename))
return false; return false;
if (a->is_inherited != b->is_inherited) if (a->inhcount != b->inhcount)
return false;
if (a->is_local != b->is_local)
return false; return false;
if (a->is_not_null != b->is_not_null) if (a->is_not_null != b->is_not_null)
return false; return false;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.174 2002/09/18 21:35:21 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.175 2002/09/22 19:42:51 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -176,8 +176,9 @@ _outColumnDef(StringInfo str, ColumnDef *node) ...@@ -176,8 +176,9 @@ _outColumnDef(StringInfo str, ColumnDef *node)
_outToken(str, node->colname); _outToken(str, node->colname);
appendStringInfo(str, " :typename "); appendStringInfo(str, " :typename ");
_outNode(str, node->typename); _outNode(str, node->typename);
appendStringInfo(str, " :is_inherited %s :is_not_null %s :raw_default ", appendStringInfo(str, " :inhcount %d :is_local %s :is_not_null %s :raw_default ",
booltostr(node->is_inherited), node->inhcount,
booltostr(node->is_local),
booltostr(node->is_not_null)); booltostr(node->is_not_null));
_outNode(str, node->raw_default); _outNode(str, node->raw_default);
appendStringInfo(str, " :cooked_default "); appendStringInfo(str, " :cooked_default ");
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.133 2002/09/18 21:35:21 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.134 2002/09/22 19:42:51 tgl Exp $
* *
* NOTES * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -1526,9 +1526,13 @@ _readColumnDef(void) ...@@ -1526,9 +1526,13 @@ _readColumnDef(void)
token = pg_strtok(&length); /* eat :typename */ token = pg_strtok(&length); /* eat :typename */
local_node->typename = nodeRead(true); /* now read it */ local_node->typename = nodeRead(true); /* now read it */
token = pg_strtok(&length); /* eat :is_inherited */ token = pg_strtok(&length); /* eat :inhcount */
token = pg_strtok(&length); /* get :is_inherited */ token = pg_strtok(&length); /* get :inhcount */
local_node->is_inherited = strtobool(token); local_node->inhcount = atoi(token);
token = pg_strtok(&length); /* eat :is_local */
token = pg_strtok(&length); /* get :is_local */
local_node->is_local = strtobool(token);
token = pg_strtok(&length); /* eat :is_not_null */ token = pg_strtok(&length); /* eat :is_not_null */
token = pg_strtok(&length); /* get :is_not_null */ token = pg_strtok(&length); /* get :is_not_null */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.368 2002/09/22 17:27:23 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.369 2002/09/22 19:42:51 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -1453,6 +1453,7 @@ columnDef: ColId Typename ColQualList opt_collate ...@@ -1453,6 +1453,7 @@ columnDef: ColId Typename ColQualList opt_collate
n->colname = $1; n->colname = $1;
n->typename = $2; n->typename = $2;
n->constraints = $3; n->constraints = $3;
n->is_local = true;
if ($4 != NULL) if ($4 != NULL)
elog(NOTICE, elog(NOTICE,
...@@ -1842,6 +1843,8 @@ CreateAsElement: ...@@ -1842,6 +1843,8 @@ CreateAsElement:
ColumnDef *n = makeNode(ColumnDef); ColumnDef *n = makeNode(ColumnDef);
n->colname = $1; n->colname = $1;
n->typename = NULL; n->typename = NULL;
n->inhcount = 0;
n->is_local = true;
n->is_not_null = false; n->is_not_null = false;
n->raw_default = NULL; n->raw_default = NULL;
n->cooked_default = NULL; n->cooked_default = NULL;
...@@ -4844,6 +4847,7 @@ TableFuncElement: ColId Typename ...@@ -4844,6 +4847,7 @@ TableFuncElement: ColId Typename
n->colname = $1; n->colname = $1;
n->typename = $2; n->typename = $2;
n->constraints = NIL; n->constraints = NIL;
n->is_local = true;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: catversion.h,v 1.159 2002/09/18 21:35:23 tgl Exp $ * $Id: catversion.h,v 1.160 2002/09/22 19:42:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200209181 #define CATALOG_VERSION_NO 200209221
#endif #endif
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pg_class.h,v 1.73 2002/09/04 20:31:37 momjian Exp $ * $Id: pg_class.h,v 1.74 2002/09/22 19:42:52 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -136,7 +136,7 @@ typedef FormData_pg_class *Form_pg_class; ...@@ -136,7 +136,7 @@ typedef FormData_pg_class *Form_pg_class;
DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ )); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 18 0 0 0 0 0 f f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 15 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 15 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parsenodes.h,v 1.207 2002/09/18 21:35:24 tgl Exp $ * $Id: parsenodes.h,v 1.208 2002/09/22 19:42:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -301,7 +301,8 @@ typedef struct ColumnDef ...@@ -301,7 +301,8 @@ typedef struct ColumnDef
NodeTag type; NodeTag type;
char *colname; /* name of column */ char *colname; /* name of column */
TypeName *typename; /* type of column */ TypeName *typename; /* type of column */
bool is_inherited; /* column is inherited? */ int inhcount; /* number of times column is inherited */
bool is_local; /* column has local (non-inherited) def'n */
bool is_not_null; /* NOT NULL constraint specified? */ bool is_not_null; /* NOT NULL constraint specified? */
Node *raw_default; /* default value (untransformed parse Node *raw_default; /* default value (untransformed parse
* tree) */ * tree) */
......
...@@ -1054,3 +1054,116 @@ alter table renameColumn add column w int; ...@@ -1054,3 +1054,116 @@ alter table renameColumn add column w int;
-- this should fail -- this should fail
alter table only renameColumn add column x int; alter table only renameColumn add column x int;
ERROR: Attribute must be added to child tables too ERROR: Attribute must be added to child tables too
-- Test corner cases in dropping of inherited columns
create table p1 (f1 int, f2 int);
create table c1 (f1 int not null) inherits(p1);
NOTICE: CREATE TABLE: merging attribute "f1" with inherited definition
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
ERROR: ALTER TABLE: Cannot drop inherited column "f1"
-- should work
alter table p1 drop column f1;
-- c1.f1 is still there, but no longer inherited
select f1 from c1;
f1
----
(0 rows)
alter table c1 drop column f1;
select f1 from c1;
ERROR: Attribute "f1" not found
drop table p1 cascade;
NOTICE: Drop cascades to table c1
create table p1 (f1 int, f2 int);
create table c1 () inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
ERROR: ALTER TABLE: Cannot drop inherited column "f1"
alter table p1 drop column f1;
-- c1.f1 is dropped now, since there is no local definition for it
select f1 from c1;
ERROR: Attribute "f1" not found
drop table p1 cascade;
NOTICE: Drop cascades to table c1
create table p1 (f1 int, f2 int);
create table c1 () inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
ERROR: ALTER TABLE: Cannot drop inherited column "f1"
alter table only p1 drop column f1;
-- c1.f1 is NOT dropped, but must now be considered non-inherited
alter table c1 drop column f1;
drop table p1 cascade;
NOTICE: Drop cascades to table c1
create table p1 (f1 int, f2 int);
create table c1 (f1 int not null) inherits(p1);
NOTICE: CREATE TABLE: merging attribute "f1" with inherited definition
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
ERROR: ALTER TABLE: Cannot drop inherited column "f1"
alter table only p1 drop column f1;
-- c1.f1 is still there, but no longer inherited
alter table c1 drop column f1;
drop table p1 cascade;
NOTICE: Drop cascades to table c1
create table p1(id int, name text);
create table p2(id2 int, name text, height int);
create table c1(age int) inherits(p1,p2);
NOTICE: CREATE TABLE: merging multiple inherited definitions of attribute "name"
create table gc1() inherits (c1);
select relname, attname, attinhcount, attislocal
from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
order by relname, attnum;
relname | attname | attinhcount | attislocal
---------+---------+-------------+------------
c1 | id | 1 | f
c1 | name | 2 | f
c1 | id2 | 1 | f
c1 | height | 1 | f
c1 | age | 0 | t
gc1 | id | 1 | f
gc1 | name | 1 | f
gc1 | id2 | 1 | f
gc1 | height | 1 | f
gc1 | age | 1 | f
p1 | id | 0 | t
p1 | name | 0 | t
p2 | id2 | 0 | t
p2 | name | 0 | t
p2 | height | 0 | t
(15 rows)
-- should work
alter table only p1 drop column name;
-- should work. Now c1.name is local and inhcount is 0.
alter table p2 drop column name;
-- should be rejected since its inherited
alter table gc1 drop column name;
ERROR: ALTER TABLE: Cannot drop inherited column "name"
-- should work, and drop gc1.name along
alter table c1 drop column name;
-- should fail: column does not exist
alter table gc1 drop column name;
ERROR: Relation "gc1" has no column "name"
-- should work and drop the attribute in all tables
alter table p2 drop column height;
select relname, attname, attinhcount, attislocal
from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
order by relname, attnum;
relname | attname | attinhcount | attislocal
---------+---------+-------------+------------
c1 | id | 1 | f
c1 | id2 | 1 | f
c1 | age | 0 | t
gc1 | id | 1 | f
gc1 | id2 | 1 | f
gc1 | age | 1 | f
p1 | id | 0 | t
p2 | id2 | 0 | t
(8 rows)
drop table p1, p2 cascade;
NOTICE: Drop cascades to table c1
NOTICE: Drop cascades to table gc1
...@@ -170,7 +170,8 @@ WHERE (p1.relkind = 'i' AND p1.relam = 0) OR ...@@ -170,7 +170,8 @@ WHERE (p1.relkind = 'i' AND p1.relam = 0) OR
SELECT p1.attrelid, p1.attname SELECT p1.attrelid, p1.attname
FROM pg_attribute as p1 FROM pg_attribute as p1
WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR
p1.attcacheoff != -1; p1.attcacheoff != -1 OR p1.attinhcount < 0 OR
(p1.attinhcount = 0 AND NOT p1.attislocal);
attrelid | attname attrelid | attname
----------+--------- ----------+---------
(0 rows) (0 rows)
......
...@@ -764,3 +764,83 @@ alter table renameColumn add column w int; ...@@ -764,3 +764,83 @@ alter table renameColumn add column w int;
-- this should fail -- this should fail
alter table only renameColumn add column x int; alter table only renameColumn add column x int;
-- Test corner cases in dropping of inherited columns
create table p1 (f1 int, f2 int);
create table c1 (f1 int not null) inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
-- should work
alter table p1 drop column f1;
-- c1.f1 is still there, but no longer inherited
select f1 from c1;
alter table c1 drop column f1;
select f1 from c1;
drop table p1 cascade;
create table p1 (f1 int, f2 int);
create table c1 () inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
alter table p1 drop column f1;
-- c1.f1 is dropped now, since there is no local definition for it
select f1 from c1;
drop table p1 cascade;
create table p1 (f1 int, f2 int);
create table c1 () inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
alter table only p1 drop column f1;
-- c1.f1 is NOT dropped, but must now be considered non-inherited
alter table c1 drop column f1;
drop table p1 cascade;
create table p1 (f1 int, f2 int);
create table c1 (f1 int not null) inherits(p1);
-- should be rejected since c1.f1 is inherited
alter table c1 drop column f1;
alter table only p1 drop column f1;
-- c1.f1 is still there, but no longer inherited
alter table c1 drop column f1;
drop table p1 cascade;
create table p1(id int, name text);
create table p2(id2 int, name text, height int);
create table c1(age int) inherits(p1,p2);
create table gc1() inherits (c1);
select relname, attname, attinhcount, attislocal
from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
order by relname, attnum;
-- should work
alter table only p1 drop column name;
-- should work. Now c1.name is local and inhcount is 0.
alter table p2 drop column name;
-- should be rejected since its inherited
alter table gc1 drop column name;
-- should work, and drop gc1.name along
alter table c1 drop column name;
-- should fail: column does not exist
alter table gc1 drop column name;
-- should work and drop the attribute in all tables
alter table p2 drop column height;
select relname, attname, attinhcount, attislocal
from pg_class join pg_attribute on (pg_class.oid = pg_attribute.attrelid)
where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
order by relname, attnum;
drop table p1, p2 cascade;
...@@ -137,7 +137,8 @@ WHERE (p1.relkind = 'i' AND p1.relam = 0) OR ...@@ -137,7 +137,8 @@ WHERE (p1.relkind = 'i' AND p1.relam = 0) OR
SELECT p1.attrelid, p1.attname SELECT p1.attrelid, p1.attname
FROM pg_attribute as p1 FROM pg_attribute as p1
WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR WHERE p1.attrelid = 0 OR p1.atttypid = 0 OR p1.attnum = 0 OR
p1.attcacheoff != -1; p1.attcacheoff != -1 OR p1.attinhcount < 0 OR
(p1.attinhcount = 0 AND NOT p1.attislocal);
-- Cross-check attnum against parent relation -- Cross-check attnum against parent relation
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment