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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers