Hello,

I am returning back to message
http://archives.postgresql.org/pgsql-general/2010-02/msg00119.php

Our implementation of variadic parameters missing correct handling
test on NULL, and test on non constant value.

This patch add correct tests for variadic parameters. Probably
Gen_fmgrtab.pl have needs some work - there are magic constants for
InvalidOid and ANYOID.

Regards

Pavel Stehule
*** ./src/backend/executor/execQual.c.orig	2010-01-11 16:31:04.000000000 +0100
--- ./src/backend/executor/execQual.c	2010-02-09 16:08:07.000000000 +0100
***************
*** 1601,1606 ****
--- 1601,1612 ----
  						break;
  					}
  				}
+ 				
+ 				/* 
+ 				 * If function is variadic, then check a variadic array argument.
+ 				 */
+ 				if (fcache->func.fn_vararg && ARR_HASNULL(DatumGetArrayTypeP(fcinfo->arg[fcinfo->nargs - 1])))
+ 					callit = false;
  			}
  
  			if (callit)
***************
*** 1738,1743 ****
--- 1744,1759 ----
  					return (Datum) 0;
  				}
  			}
+ 			
+ 			/* 
+ 			 * Check variadic argument. If array with variadic arguments
+ 			 * contains NULLs, then return NULL.
+ 			 */
+ 			if (fcache->func.fn_vararg && ARR_HASNULL(DatumGetArrayTypeP(fcinfo->arg[fcinfo->nargs - 1])))
+ 			{
+ 				*isNull = true;
+ 				return (Datum) 0;
+ 			}
  		}
  
  		pgstat_init_function_usage(fcinfo, &fcusage);
***************
*** 1805,1810 ****
--- 1821,1836 ----
  				return (Datum) 0;
  			}
  		}
+ 		
+ 		/*
+ 		 * If function has variadic argument, skip calling
+ 		 * when variadic array contains NULL values.
+ 		 */
+ 		if (fcache->func.fn_vararg && ARR_HASNULL(DatumGetArrayTypeP(fcinfo.arg[fcinfo.nargs - 1])))
+ 		{
+ 			*isNull = true;
+ 			return (Datum) 0;
+ 		}
  	}
  
  	pgstat_init_function_usage(&fcinfo, &fcusage);
*** ./src/backend/optimizer/util/clauses.c.orig	2010-01-19 17:33:33.000000000 +0100
--- ./src/backend/optimizer/util/clauses.c	2010-02-09 12:04:57.000000000 +0100
***************
*** 3588,3599 ****
  	/*
  	 * Check for constant inputs and especially constant-NULL inputs.
  	 */
! 	foreach(arg, args)
  	{
! 		if (IsA(lfirst(arg), Const))
! 			has_null_input |= ((Const *) lfirst(arg))->constisnull;
! 		else
! 			has_nonconst_input = true;
  	}
  
  	/*
--- 3588,3643 ----
  	/*
  	 * Check for constant inputs and especially constant-NULL inputs.
  	 */
! 	if (OidIsValid(funcform->provariadic) && funcform->provariadic != ANYOID)
  	{
! 		foreach(arg, args)
! 		{
! 			if (lnext(arg) != NULL)
! 			{
! 				/* Check non variriadic arguments. */
! 				if (IsA(lfirst(arg), Const))
! 					has_null_input |= ((Const *) lfirst(arg))->constisnull;
! 				else
! 					has_nonconst_input = true;
! 			}
! 			else
! 			{
! 				Node *vararg = lfirst(arg);
! 				ListCell	*lc;
! 				
! 				/* Variadic argument is array. Check fields */
! 				if (IsA(vararg, ArrayExpr))
! 				{
! 					foreach(lc, ((ArrayExpr *) vararg)->elements)
! 					{
! 						if (IsA(lfirst(lc), Const))
! 							has_null_input |= ((Const *) lfirst(lc))->constisnull;
! 						else
! 							has_nonconst_input = true;
! 					}
! 				}
! 				else 
! 				{
! 					Assert(IsA(vararg, Const));
! 					
! 					if (((Const *) vararg)->constisnull)
! 						has_null_input = true;
! 					else
! 						has_null_input |= ARR_HASNULL(DatumGetArrayTypeP(((Const *) vararg)->constvalue));
! 				}
! 			}
! 		}
! 	}
! 	else
! 	{
! 		/* simpler and faster form for nonvariadic function or variadic "any" */
! 		foreach(arg, args)
! 		{
! 			if (IsA(lfirst(arg), Const))
! 				has_null_input |= ((Const *) lfirst(arg))->constisnull;
! 			else
! 				has_nonconst_input = true;
! 		}
  	}
  
  	/*
*** ./src/backend/utils/fmgr/fmgr.c.orig	2010-01-07 05:53:34.000000000 +0100
--- ./src/backend/utils/fmgr/fmgr.c	2010-02-09 14:42:42.000000000 +0100
***************
*** 18,23 ****
--- 18,24 ----
  #include "access/tuptoaster.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_proc.h"
+ #include "catalog/pg_type.h"
  #include "executor/functions.h"
  #include "executor/spi.h"
  #include "lib/stringinfo.h"
***************
*** 199,204 ****
--- 200,206 ----
  		finfo->fn_nargs = fbp->nargs;
  		finfo->fn_strict = fbp->strict;
  		finfo->fn_retset = fbp->retset;
+ 		finfo->fn_vararg = fbp->vararg;
  		finfo->fn_stats = TRACK_FUNC_ALL;		/* ie, never track */
  		finfo->fn_addr = fbp->func;
  		finfo->fn_oid = functionId;
***************
*** 216,221 ****
--- 218,224 ----
  	finfo->fn_nargs = procedureStruct->pronargs;
  	finfo->fn_strict = procedureStruct->proisstrict;
  	finfo->fn_retset = procedureStruct->proretset;
+ 	finfo->fn_vararg = OidIsValid(procedureStruct->provariadic) && procedureStruct->provariadic != ANYOID;
  
  	/*
  	 * If it has prosecdef set, or non-null proconfig, use
*** ./src/backend/utils/Gen_fmgrtab.pl.orig	2010-01-05 21:23:32.000000000 +0100
--- ./src/backend/utils/Gen_fmgrtab.pl	2010-02-09 14:23:04.000000000 +0100
***************
*** 77,82 ****
--- 77,83 ----
          oid    => $row->{oid},
          strict => $row->{proisstrict},
          retset => $row->{proretset},
+         vararg => ($row->{provariadic} != 0 && $row->{provariadic} != 2276) ? 't' : 'f',
          nargs  => $row->{pronargs},
          prosrc => $row->{prosrc},
        };
***************
*** 176,182 ****
  foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr)
  {
      print T
! 	"  { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $s->{prosrc} },\n";
  }
  
  # And add the file footers.
--- 177,183 ----
  foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr)
  {
      print T
! 	"  { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $bmap{$s->{vararg}}, $s->{prosrc} },\n";
  }
  
  # And add the file footers.
*** ./src/include/fmgr.h.orig	2010-02-08 21:39:52.000000000 +0100
--- ./src/include/fmgr.h	2010-02-09 14:30:55.000000000 +0100
***************
*** 49,54 ****
--- 49,55 ----
  								 * count */
  	bool		fn_strict;		/* function is "strict" (NULL in => NULL out) */
  	bool		fn_retset;		/* function returns a set */
+ 	bool		fn_vararg;		/* function has a variadic (packed) parameter */
  	unsigned char fn_stats;		/* collect stats if track_functions > this */
  	void	   *fn_extra;		/* extra space for use by handler */
  	MemoryContext fn_mcxt;		/* memory context to store fn_extra in */
*** ./src/include/utils/fmgrtab.h.orig	2010-01-02 17:58:10.000000000 +0100
--- ./src/include/utils/fmgrtab.h	2010-02-09 13:47:40.000000000 +0100
***************
*** 29,34 ****
--- 29,35 ----
  	short		nargs;			/* 0..FUNC_MAX_ARGS, or -1 if variable count */
  	bool		strict;			/* T if function is "strict" */
  	bool		retset;			/* T if function returns a set */
+ 	bool		vararg;			/* T if function has a packed variadic argument */
  	PGFunction	func;			/* pointer to compiled function */
  } FmgrBuiltin;
  
*** ./src/test/regress/expected/plpgsql.out.orig	2010-01-26 17:33:40.000000000 +0100
--- ./src/test/regress/expected/plpgsql.out	2010-02-09 16:24:22.000000000 +0100
***************
*** 4107,4109 ****
--- 4107,4165 ----
  (1 row)
  
  drop function unreserved_test();
+ -- check strict variadic functions
+ create or replace function concate(variadic str text[])
+ returns text as $$
+ declare 
+   s text = '';
+   f text;
+ begin
+   raise notice 'start concate';
+   for f in select unnest(str) 
+   loop
+     s := s || coalesce(f,'');
+   end loop;
+   return s;
+ end;
+ $$ language plpgsql strict;
+ create table strict_test(a text);
+ insert into strict_test values('some text'),(NULL), ('some text');
+ select concate('a','b') from strict_test;
+ NOTICE:  start concate
+ NOTICE:  start concate
+ NOTICE:  start concate
+  concate 
+ ---------
+  ab
+  ab
+  ab
+ (3 rows)
+ 
+ select concate('a','b', null) from strict_test;
+  concate 
+ ---------
+  
+  
+  
+ (3 rows)
+ 
+ select concate(a,'b') from strict_test;
+ NOTICE:  start concate
+ NOTICE:  start concate
+   concate   
+ ------------
+  some textb
+  
+  some textb
+ (3 rows)
+ 
+ select concate(a, null) from strict_test;
+  concate 
+ ---------
+  
+  
+  
+ (3 rows)
+ 
+ drop function concate(variadic text[]);
+ drop table strict_test;
*** ./src/test/regress/sql/plpgsql.sql.orig	2010-01-26 17:33:40.000000000 +0100
--- ./src/test/regress/sql/plpgsql.sql	2010-02-09 16:23:41.000000000 +0100
***************
*** 3254,3256 ****
--- 3254,3284 ----
  select unreserved_test();
  
  drop function unreserved_test();
+ 
+ -- check strict variadic functions
+ create or replace function concate(variadic str text[])
+ returns text as $$
+ declare 
+   s text = '';
+   f text;
+ begin
+   raise notice 'start concate';
+   for f in select unnest(str) 
+   loop
+     s := s || coalesce(f,'');
+   end loop;
+   return s;
+ end;
+ $$ language plpgsql strict;
+ 
+ create table strict_test(a text);
+ 
+ insert into strict_test values('some text'),(NULL), ('some text');
+ 
+ select concate('a','b') from strict_test;
+ select concate('a','b', null) from strict_test;
+ select concate(a,'b') from strict_test;
+ select concate(a, null) from strict_test;
+ 
+ drop function concate(variadic text[]);
+ drop table strict_test;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to