Hello

there is fix for bug Re: [BUGS] BUG #4907: stored procedures and changed tables

regards
Pavel Stehule


2009/7/10 Sergey Burladyan <eshkin...@gmail.com>:
> Sergey Burladyan <eshkin...@gmail.com> writes:
>
>> Alvaro Herrera <alvhe...@commandprompt.com> writes:
>>
>> > Michael Tenenbaum wrote:
>> >
>> > > If I have a stored procedure that returns a set of records of a table, I 
>> > > get
>> > > an error message that the procedure's record is the wrong type after I
>> > > change some columns in the table.
>> > >
>> > > Deleting the procedure then rewriting the procedure does not help.  The 
>> > > only
>> > > thing that works is deleting both the stored procedure and the table and
>> > > starting over again.
>> >
>> > Does it work if you disconnect and connect again?
>>
>> No, example:
>
> More simple:
>
> PostgreSQL 8.4.0 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 
> 4.3.3-13) 4.3.3, 32-bit
>
>  create table t (i int);
>  alter table t add v text; alter table t drop i;
>  create function foo() returns setof t language plpgsql as $$begin return 
> query select * from t; end$$;
>  select foo();
> ERROR:  42804: structure of query does not match function result type
> ПОДРОБНО:  Number of returned columns (1) does not match expected column 
> count (2).
> КОНТЕКСТ:  PL/pgSQL function "foo" line 1 at RETURN QUERY
> РАСПОЛОЖЕНИЕ:  validate_tupdesc_compat, pl_exec.c:5143
>
> So, function with RETURNS SETOF tbl does not work if it created after ALTER 
> TABLE
>
> 8.3.7 too:
>
> PostgreSQL 8.3.7 on i486-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 
> 4.3.3-5) 4.3.3
>
>  create table t (i int);
>  alter table t add v text; alter table t drop i;
>  create function foo() returns setof t language plpgsql as $$begin return 
> query select * from t; end$$;
>  select * from foo();
> ERROR:  42804: structure of query does not match function result type
> КОНТЕКСТ:  PL/pgSQL function "foo" line 1 at RETURN QUERY
> РАСПОЛОЖЕНИЕ:  exec_stmt_return_query, pl_exec.c:2173
>
>
> --
> Sergey Burladyan
>
> --
> Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-bugs
>
*** ./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 $$
-- 
Sent via pgsql-bugs mailing list (pgsql-bugs@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-bugs

Reply via email to