*** ./src/pl/plpgsql/src/pl_exec.c.orig 2009-07-12 17:22:57.268901328 +0200 --- ./src/pl/plpgsql/src/pl_exec.c 2009-07-12 16:57:37.037896969 +0200 *************** *** 2284,2289 **** --- 2284,2294 ---- { Portal portal; uint32 processed = 0; + int i; + bool dropped_columns = false; + Datum *dvalues; + bool *nulls; + int natts; if (!estate->retisset) ereport(ERROR, *************** *** 2308,2318 **** validate_tupdesc_compat(estate->rettupdesc, portal->tupDesc, "structure of query does not match function result type"); while (true) { MemoryContext old_cxt; - int i; SPI_cursor_fetch(portal, true, 50); if (SPI_processed == 0) --- 2313,2330 ---- validate_tupdesc_compat(estate->rettupdesc, portal->tupDesc, "structure of query does not match function result type"); + natts = estate->rettupdesc->natts; + + if (natts > portal->tupDesc->natts) + { + dropped_columns = true; + dvalues = (Datum *) palloc0(natts * sizeof(Datum)); + nulls = (bool *) palloc(natts * sizeof(bool)); + } while (true) { MemoryContext old_cxt; SPI_cursor_fetch(portal, true, 50); if (SPI_processed == 0) *************** *** 2323,2335 **** { HeapTuple tuple = SPI_tuptable->vals[i]; ! tuplestore_puttuple(estate->tuple_store, tuple); processed++; } MemoryContextSwitchTo(old_cxt); SPI_freetuptable(SPI_tuptable); } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); --- 2335,2374 ---- { HeapTuple tuple = SPI_tuptable->vals[i]; ! if (!dropped_columns) ! tuplestore_puttuple(estate->tuple_store, tuple); ! else ! { ! int anum; ! int j = 0; ! bool isnull; ! ! for (anum = 0; anum < natts; anum++) ! { ! if (estate->rettupdesc->attrs[anum]->attisdropped) ! nulls[anum] = true; ! else ! { ! dvalues[anum] = SPI_getbinval(tuple, portal->tupDesc, ! ++j, &isnull); ! nulls[anum] = isnull; ! } ! } ! tuple = heap_form_tuple(estate->rettupdesc, dvalues, nulls); ! tuplestore_puttuple(estate->tuple_store, tuple); ! } processed++; } MemoryContextSwitchTo(old_cxt); SPI_freetuptable(SPI_tuptable); } + + if (dropped_columns) + { + pfree(dvalues); + pfree(nulls); + } SPI_freetuptable(SPI_tuptable); SPI_cursor_close(portal); *************** *** 5127,5132 **** --- 5166,5172 ---- validate_tupdesc_compat(TupleDesc expected, TupleDesc returned, const char *msg) { int i; + int j = 0; const char *dropped_column_type = gettext_noop("N/A (dropped column)"); if (!expected || !returned) *************** *** 5134,5153 **** (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("%s", _(msg)))); - if (expected->natts != returned->natts) - ereport(ERROR, - (errcode(ERRCODE_DATATYPE_MISMATCH), - errmsg("%s", _(msg)), - errdetail("Number of returned columns (%d) does not match " - "expected column count (%d).", - returned->natts, expected->natts))); - for (i = 0; i < expected->natts; i++) ! if (expected->attrs[i]->atttypid != returned->attrs[i]->atttypid) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("%s", _(msg)), ! errdetail("Returned type %s does not match expected type " "%s in column \"%s\".", OidIsValid(returned->attrs[i]->atttypid) ? format_type_be(returned->attrs[i]->atttypid) : --- 5174,5186 ---- (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("%s", _(msg)))); for (i = 0; i < expected->natts; i++) ! if (!expected->attrs[i]->attisdropped) ! if (expected->attrs[i]->atttypid != returned->attrs[j++]->atttypid) ! ereport(ERROR, ! (errcode(ERRCODE_DATATYPE_MISMATCH), ! errmsg("%s", _(msg)), ! errdetail("Returned type %s does not match expected type " "%s in column \"%s\".", OidIsValid(returned->attrs[i]->atttypid) ? format_type_be(returned->attrs[i]->atttypid) : *** ./src/test/regress/expected/plpgsql.out.orig 2009-07-12 17:19:13.471901827 +0200 --- ./src/test/regress/expected/plpgsql.out 2009-07-12 17:20:34.917899093 +0200 *************** *** 3285,3290 **** --- 3285,3342 ---- (4 rows) drop function return_dquery(); + -- fix return query and dropped columns bug + create table tabwithcols(a int, b int, c int, d int); + insert into tabwithcols values(10,20,30,40),(50,60,70,80); + create or replace function returnqueryf() + returns setof tabwithcols as $$ + begin + return query select * from tabwithcols; + return query execute 'select * from tabwithcols'; + end; + $$ language plpgsql; + select * from returnqueryf(); + a | b | c | d + ----+----+----+---- + 10 | 20 | 30 | 40 + 50 | 60 | 70 | 80 + 10 | 20 | 30 | 40 + 50 | 60 | 70 | 80 + (4 rows) + + alter table tabwithcols drop column b; + alter table tabwithcols drop column c; + select * from returnqueryf(); + a | d + ----+---- + 10 | 40 + 50 | 80 + 10 | 40 + 50 | 80 + (4 rows) + + alter table tabwithcols drop column d; + select * from returnqueryf(); + a + ---- + 10 + 50 + 10 + 50 + (4 rows) + + alter table tabwithcols add column d int; + select * from returnqueryf(); + a | d + ----+--- + 10 | + 50 | + 10 | + 50 | + (4 rows) + + drop function returnqueryf(); + drop table tabwithcols; -- Tests for 8.4's new RAISE features create or replace function raise_test() returns void as $$ begin *** ./src/test/regress/sql/plpgsql.sql.orig 2009-07-12 17:10:26.186902373 +0200 --- ./src/test/regress/sql/plpgsql.sql 2009-07-12 17:19:00.836898296 +0200 *************** *** 2684,2689 **** --- 2684,2719 ---- drop function return_dquery(); + -- fix return query and dropped columns bug + create table tabwithcols(a int, b int, c int, d int); + insert into tabwithcols values(10,20,30,40),(50,60,70,80); + + create or replace function returnqueryf() + returns setof tabwithcols as $$ + begin + return query select * from tabwithcols; + return query execute 'select * from tabwithcols'; + end; + $$ language plpgsql; + + select * from returnqueryf(); + + alter table tabwithcols drop column b; + alter table tabwithcols drop column c; + + select * from returnqueryf(); + + alter table tabwithcols drop column d; + + select * from returnqueryf(); + + alter table tabwithcols add column d int; + + select * from returnqueryf(); + + drop function returnqueryf(); + drop table tabwithcols; + -- Tests for 8.4's new RAISE features create or replace function raise_test() returns void as $$