aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execExprInterp.c45
-rw-r--r--src/test/regress/expected/create_view.out47
-rw-r--r--src/test/regress/expected/rangefuncs.out19
-rw-r--r--src/test/regress/sql/create_view.sql25
-rw-r--r--src/test/regress/sql/rangefuncs.sql6
5 files changed, 95 insertions, 47 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 982d16c6c88..4fbb5c1e746 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1516,22 +1516,20 @@ CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
{
/*
* What we have to check for here is the possibility of an attribute
- * having been changed in type since the plan tree was created. Ideally
- * the plan will get invalidated and not re-used, but just in case, we
- * keep these defenses. Fortunately it's sufficient to check once on the
- * first time through.
- *
- * System attributes don't require checking since their types never
- * change.
- *
- * Note: we allow a reference to a dropped attribute. slot_getattr will
- * force a NULL result in such cases.
+ * having been dropped or changed in type since the plan tree was created.
+ * Ideally the plan will get invalidated and not re-used, but just in
+ * case, we keep these defenses. Fortunately it's sufficient to check
+ * once on the first time through.
*
* Note: ideally we'd check typmod as well as typid, but that seems
* impractical at the moment: in many cases the tupdesc will have been
* generated by ExecTypeFromTL(), and that can't guarantee to generate an
* accurate typmod in all cases, because some expression node types don't
- * carry typmod.
+ * carry typmod. Fortunately, for precisely that reason, there should be
+ * no places with a critical dependency on the typmod of a value.
+ *
+ * System attributes don't require checking since their types never
+ * change.
*/
if (attnum > 0)
{
@@ -1544,17 +1542,20 @@ CheckVarSlotCompatibility(TupleTableSlot *slot, int attnum, Oid vartype)
attr = slot_tupdesc->attrs[attnum - 1];
- /* can't check type if dropped, since atttypid is probably 0 */
- if (!attr->attisdropped)
- {
- if (vartype != attr->atttypid)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("attribute %d has wrong type", attnum),
- errdetail("Table has type %s, but query expects %s.",
- format_type_be(attr->atttypid),
- format_type_be(vartype))));
- }
+ if (attr->attisdropped)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("attribute %d of type %s has been dropped",
+ attnum, format_type_be(slot_tupdesc->tdtypeid))));
+
+ if (vartype != attr->atttypid)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("attribute %d of type %s has wrong type",
+ attnum, format_type_be(slot_tupdesc->tdtypeid)),
+ errdetail("Table has type %s, but query expects %s.",
+ format_type_be(attr->atttypid),
+ format_type_be(vartype))));
}
}
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index ce0c8cedf89..c719262720e 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1396,10 +1396,10 @@ select pg_get_viewdef('vv6', true);
(1 row)
--
--- Check some cases involving dropped columns in a function's rowtype result
+-- Check cases involving dropped/altered columns in a function's rowtype result
--
create table tt14t (f1 text, f2 text, f3 text, f4 text);
-insert into tt14t values('foo', 'bar', 'baz', 'quux');
+insert into tt14t values('foo', 'bar', 'baz', '42');
alter table tt14t drop column f2;
create function tt14f() returns setof tt14t as
$$
@@ -1424,14 +1424,15 @@ select pg_get_viewdef('tt14v', true);
(1 row)
select * from tt14v;
- f1 | f3 | f4
------+-----+------
- foo | baz | quux
+ f1 | f3 | f4
+-----+-----+----
+ foo | baz | 42
(1 row)
+begin;
-- this perhaps should be rejected, but it isn't:
alter table tt14t drop column f3;
--- f3 is still in the view but will read as nulls
+-- f3 is still in the view ...
select pg_get_viewdef('tt14v', true);
pg_get_viewdef
--------------------------------
@@ -1441,12 +1442,40 @@ select pg_get_viewdef('tt14v', true);
FROM tt14f() t(f1, f3, f4);
(1 row)
+-- but will fail at execution
+select f1, f4 from tt14v;
+ f1 | f4
+-----+----
+ foo | 42
+(1 row)
+
select * from tt14v;
- f1 | f3 | f4
------+----+------
- foo | | quux
+ERROR: attribute 3 of type record has been dropped
+rollback;
+begin;
+-- this perhaps should be rejected, but it isn't:
+alter table tt14t alter column f4 type integer using f4::integer;
+-- f4 is still in the view ...
+select pg_get_viewdef('tt14v', true);
+ pg_get_viewdef
+--------------------------------
+ SELECT t.f1, +
+ t.f3, +
+ t.f4 +
+ FROM tt14f() t(f1, f3, f4);
(1 row)
+-- but will fail at execution
+select f1, f3 from tt14v;
+ f1 | f3
+-----+-----
+ foo | baz
+(1 row)
+
+select * from tt14v;
+ERROR: attribute 4 of type record has wrong type
+DETAIL: Table has type integer, but query expects text.
+rollback;
-- check display of whole-row variables in some corner cases
create type nestedcomposite as (x int8_tbl);
create view tt15v as select row(i)::nestedcomposite from int8_tbl i;
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 526a4aed0a2..4b6170dea5a 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -1909,25 +1909,22 @@ select * from usersview;
id2 | 2 | email2 | 12 | t | 11 | 2
(2 rows)
-alter table users drop column moredrop;
-select * from usersview;
- userid | seq | email | moredrop | enabled | generate_series | ordinality
---------+-----+--------+----------+---------+-----------------+------------
- id | 1 | email | | t | 10 | 1
- id2 | 2 | email2 | | t | 11 | 2
-(2 rows)
-
alter table users add column junk text;
select * from usersview;
userid | seq | email | moredrop | enabled | generate_series | ordinality
--------+-----+--------+----------+---------+-----------------+------------
- id | 1 | email | | t | 10 | 1
- id2 | 2 | email2 | | t | 11 | 2
+ id | 1 | email | 11 | t | 10 | 1
+ id2 | 2 | email2 | 12 | t | 11 | 2
(2 rows)
+begin;
+alter table users drop column moredrop;
+select * from usersview; -- expect clean failure
+ERROR: attribute 5 of type record has been dropped
+rollback;
alter table users alter column seq type numeric;
select * from usersview; -- expect clean failure
-ERROR: attribute 2 has wrong type
+ERROR: attribute 2 of type record has wrong type
DETAIL: Table has type numeric, but query expects integer.
drop view usersview;
drop function get_first_user();
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index c27f1034e13..d6f50d6105f 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -457,11 +457,11 @@ alter table tt11 add column z int;
select pg_get_viewdef('vv6', true);
--
--- Check some cases involving dropped columns in a function's rowtype result
+-- Check cases involving dropped/altered columns in a function's rowtype result
--
create table tt14t (f1 text, f2 text, f3 text, f4 text);
-insert into tt14t values('foo', 'bar', 'baz', 'quux');
+insert into tt14t values('foo', 'bar', 'baz', '42');
alter table tt14t drop column f2;
@@ -483,13 +483,32 @@ create view tt14v as select t.* from tt14f() t;
select pg_get_viewdef('tt14v', true);
select * from tt14v;
+begin;
+
-- this perhaps should be rejected, but it isn't:
alter table tt14t drop column f3;
--- f3 is still in the view but will read as nulls
+-- f3 is still in the view ...
select pg_get_viewdef('tt14v', true);
+-- but will fail at execution
+select f1, f4 from tt14v;
select * from tt14v;
+rollback;
+
+begin;
+
+-- this perhaps should be rejected, but it isn't:
+alter table tt14t alter column f4 type integer using f4::integer;
+
+-- f4 is still in the view ...
+select pg_get_viewdef('tt14v', true);
+-- but will fail at execution
+select f1, f3 from tt14v;
+select * from tt14v;
+
+rollback;
+
-- check display of whole-row variables in some corner cases
create type nestedcomposite as (x int8_tbl);
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index 09ac8fbdb4d..4ed84b1f2b3 100644
--- a/src/test/regress/sql/rangefuncs.sql
+++ b/src/test/regress/sql/rangefuncs.sql
@@ -556,10 +556,12 @@ create temp view usersview as
SELECT * FROM ROWS FROM(get_users(), generate_series(10,11)) WITH ORDINALITY;
select * from usersview;
-alter table users drop column moredrop;
-select * from usersview;
alter table users add column junk text;
select * from usersview;
+begin;
+alter table users drop column moredrop;
+select * from usersview; -- expect clean failure
+rollback;
alter table users alter column seq type numeric;
select * from usersview; -- expect clean failure