/* * Verify that tupledesc associated with proposed new view definition * matches tupledesc of old view. This is basically a cut-down version * of equalTupleDescs(), with code added to generate specific complaints. * Also, we allow the new tupledesc to have more columns than the old. */ staticvoid checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) { int i;
if (newdesc->natts < olddesc->natts) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot drop columns from view")));
for (i = 0; i < olddesc->natts; i++) { Form_pg_attribute newattr = TupleDescAttr(newdesc, i); Form_pg_attribute oldattr = TupleDescAttr(olddesc, i);
/* XXX msg not right, but we don't support DROP COL on view anyway */ if (newattr->attisdropped != oldattr->attisdropped) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot drop columns from view")));
if (strcmp(NameStr(newattr->attname), NameStr(oldattr->attname)) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot change name of view column \"%s\" to \"%s\"", NameStr(oldattr->attname), NameStr(newattr->attname)), errhint("Use ALTER VIEW ... RENAME COLUMN ... to change name of view column instead."))); /* XXX would it be safe to allow atttypmod to change? Not sure */ if (newattr->atttypid != oldattr->atttypid || newattr->atttypmod != oldattr->atttypmod) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot change data type of view column \"%s\" from %s to %s", NameStr(oldattr->attname), format_type_with_typemod(oldattr->atttypid, oldattr->atttypmod), format_type_with_typemod(newattr->atttypid, newattr->atttypmod)))); /* We can ignore the remaining attributes of an attribute... */ }
/* * We ignore the constraint fields. The new view desc can't have any * constraints, and the only ones that could be on the old view are * defaults, which we are happy to leave in place. */ }
/* * If new attributes have been added, we must add pg_attribute entries * for them. It is convenient (although overkill) to use the ALTER * TABLE ADD COLUMN infrastructure for this. * * Note that we must do this before updating the query for the view, * since the rules system requires that the correct view columns be in * place when defining the new rules. * * Also note that ALTER TABLE doesn't run parse transformation on * AT_AddColumnToView commands. The ColumnDef we supply must be ready * to execute as-is. */ if (list_length(attrList) > rel->rd_att->natts) { ListCell *c; int skip = rel->rd_att->natts;
index e183ab097c44cda951696e1b2f2250118344c72c..459e9821d08142fb66f901e554c6a894b528d3bf 100644 (file) --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -282,7 +282,12 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) NameStr(oldattr->attname), NameStr(newattr->attname)), errhint("Use ALTER VIEW ... RENAME COLUMN ... to change name of view column instead."))); - /* XXX would it be safe to allow atttypmod to change? Not sure */ + + /* + * We cannot allow type, typmod, or collation to change, since these + * properties may be embedded in Vars of other views/rules referencing + * this one. Other column attributes can be ignored. + */ if (newattr->atttypid != oldattr->atttypid || newattr->atttypmod != oldattr->atttypmod) ereport(ERROR, @@ -293,7 +298,18 @@ checkViewTupleDesc(TupleDesc newdesc, TupleDesc olddesc) oldattr->atttypmod), format_type_with_typemod(newattr->atttypid, newattr->atttypmod)))); - /* We can ignore the remaining attributes of an attribute... */ + + /* + * At this point, attcollations should be both valid or both invalid, + * so applying get_collation_name unconditionally should be fine. + */ + if (newattr->attcollation != oldattr->attcollation) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot change collation of view column \"%s\" from \"%s\" to \"%s\"", + NameStr(oldattr->attname), + get_collation_name(oldattr->attcollation), + get_collation_name(newattr->attcollation)))); }