1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +03:00

Allow CREATE OR REPLACE VIEW to add columns to the _end_ of the view.

Robert Haas
This commit is contained in:
Bruce Momjian
2008-12-06 23:22:46 +00:00
parent 31076c8beb
commit ff1ea2173a
7 changed files with 97 additions and 49 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.271 2008/11/19 10:34:51 heikki Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.272 2008/12/06 23:22:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2334,6 +2334,12 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
ATSimplePermissions(rel, true);
/* Performs own recursion */
ATPrepAddColumn(wqueue, rel, recurse, cmd);
pass = AT_PASS_ADD_COL;
break;
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
/*
@@ -2555,6 +2561,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
switch (cmd->subtype)
{
case AT_AddColumn: /* ADD COLUMN */
case AT_AddColumnToView: /* add column via CREATE OR REPLACE VIEW */
ATExecAddColumn(tab, rel, (ColumnDef *) cmd->def);
break;
case AT_ColumnDefault: /* ALTER COLUMN DEFAULT */
@@ -3455,6 +3462,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
int i;
int minattnum,
maxatts;
char relkind;
HeapTuple typeTuple;
Oid typeOid;
int32 typmod;
@@ -3527,6 +3535,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
colDef->colname, RelationGetRelationName(rel))));
minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
relkind = ((Form_pg_class) GETSTRUCT(reltup))->relkind;
maxatts = minattnum + 1;
if (maxatts > MaxHeapAttributeNumber)
ereport(ERROR,
@@ -3625,45 +3634,49 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
* Note: we use build_column_default, and not just the cooked default
* returned by AddRelationNewConstraints, so that the right thing happens
* when a datatype's default applies.
*
* We skip this logic completely for views.
*/
defval = (Expr *) build_column_default(rel, attribute.attnum);
if (relkind != RELKIND_VIEW) {
defval = (Expr *) build_column_default(rel, attribute.attnum);
if (!defval && GetDomainConstraints(typeOid) != NIL)
{
Oid baseTypeId;
int32 baseTypeMod;
if (!defval && GetDomainConstraints(typeOid) != NIL)
{
Oid baseTypeId;
int32 baseTypeMod;
baseTypeMod = typmod;
baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod);
defval = (Expr *) coerce_to_target_type(NULL,
(Node *) defval,
baseTypeId,
typeOid,
typmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
if (defval == NULL) /* should not happen */
elog(ERROR, "failed to coerce base type to domain");
baseTypeMod = typmod;
baseTypeId = getBaseTypeAndTypmod(typeOid, &baseTypeMod);
defval = (Expr *) makeNullConst(baseTypeId, baseTypeMod);
defval = (Expr *) coerce_to_target_type(NULL,
(Node *) defval,
baseTypeId,
typeOid,
typmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
if (defval == NULL) /* should not happen */
elog(ERROR, "failed to coerce base type to domain");
}
if (defval)
{
NewColumnValue *newval;
newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
newval->attnum = attribute.attnum;
newval->expr = defval;
tab->newvals = lappend(tab->newvals, newval);
}
/*
* If the new column is NOT NULL, tell Phase 3 it needs to test that.
*/
tab->new_notnull |= colDef->is_not_null;
}
if (defval)
{
NewColumnValue *newval;
newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
newval->attnum = attribute.attnum;
newval->expr = defval;
tab->newvals = lappend(tab->newvals, newval);
}
/*
* If the new column is NOT NULL, tell Phase 3 it needs to test that.
*/
tab->new_notnull |= colDef->is_not_null;
/*
* Add needed dependency entries for the new column.
*/

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.107 2008/08/25 22:42:32 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.108 2008/12/06 23:22:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -172,9 +172,34 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
*/
Assert(relation->istemp == rel->rd_istemp);
/*
* If new attributes have been added, we must modify the pre-existing
* view.
*/
if (list_length(attrList) > rel->rd_att->natts) {
List *atcmds = NIL;
ListCell *c;
int skip = rel->rd_att->natts;
foreach(c, attrList) {
AlterTableCmd *atcmd;
if (skip > 0) {
--skip;
continue;
}
atcmd = makeNode(AlterTableCmd);
atcmd->subtype = AT_AddColumnToView;
atcmd->def = lfirst(c);
atcmds = lappend(atcmds, atcmd);
}
AlterTableInternal(viewOid, atcmds, true);
}
/*
* Create a tuple descriptor to compare against the existing view, and
* verify it matches.
* verify that the old column list is an initial prefix of the new
* column list.
*/
descriptor = BuildDescForRelation(attrList);
checkViewTupleDesc(descriptor, rel->rd_att);
@@ -219,13 +244,13 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
{
int i;
if (newdesc->natts != olddesc->natts)
if (newdesc->natts < olddesc->natts)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot change number of columns in view")));
errmsg("cannot drop columns from view")));
/* we can ignore tdhasoid */
for (i = 0; i < newdesc->natts; i++)
for (i = 0; i < olddesc->natts; i++)
{
Form_pg_attribute newattr = newdesc->attrs[i];
Form_pg_attribute oldattr = olddesc->attrs[i];
@@ -234,7 +259,7 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc)
if (newattr->attisdropped != oldattr->attisdropped)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot change number of columns in view")));
errmsg("cannot drop columns from view")));
if (strcmp(NameStr(newattr->attname), NameStr(oldattr->attname)) != 0)
ereport(ERROR,