Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread Andrew Dunstan


On 3/11/19 6:07 PM, Tom Lane wrote:
> Andrew Dunstan  writes:
>> I'm going to mark this as rejected. Here's a possible doc patch
> Maybe s/strictly/ordinary/, or some other word?  "strictly"
> doesn't convey much to me.  Otherwise seems fine.


OK, done.


cheers


andrew

-- 
Andrew Dunstanhttps://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread David G. Johnston
On Mon, Mar 11, 2019 at 3:07 PM Tom Lane  wrote:
>
> Andrew Dunstan  writes:
> > I'm going to mark this as rejected. Here's a possible doc patch
>
> Maybe s/strictly/ordinary/, or some other word?  "strictly"
> doesn't convey much to me.  Otherwise seems fine.
>

How about:

While the COALESCE, GREATEST, and LEAST functions below accept a
variable number of arguments they do not support the passing of a
VARIADIC array.

?

David J.



Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread Tom Lane
Andrew Dunstan  writes:
> I'm going to mark this as rejected. Here's a possible doc patch

Maybe s/strictly/ordinary/, or some other word?  "strictly"
doesn't convey much to me.  Otherwise seems fine.

regards, tom lane



Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread Pavel Stehule
po 11. 3. 2019 v 18:04 odesílatel David Steele  napsal:

> On 3/11/19 6:43 PM, Andrew Dunstan wrote:
> >
> > On 3/6/19 10:24 AM, Chapman Flack wrote:
> >> On 3/6/19 10:12 AM, Andrew Dunstan wrote:
> >>
> >>> Having reviewed the thread, I'm with Andres and Tom. Maybe though we
> >>> should have a note somewhere to the effect that you can't use VARIADIC
> >>> with these.
> >> Perhaps such a note belongs hoisted into the functions-conditional
> >> section of the manual, making a general observation that these things
> >> are conditional *expressions* that may resemble functions, but in
> >> particular, COALESCE, GREATEST, and LEAST cannot be called with
> >> keyword VARIADIC and an array argument, as they could if they were
> >> ordinary functions.
> >>
> >
> >
> > I'm going to mark this as rejected. Here's a possible doc patch
>
> +1
>
>
ok

Pavel

-- 
> -David
> da...@pgmasters.net
>


Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread David Steele

On 3/11/19 6:43 PM, Andrew Dunstan wrote:


On 3/6/19 10:24 AM, Chapman Flack wrote:

On 3/6/19 10:12 AM, Andrew Dunstan wrote:


Having reviewed the thread, I'm with Andres and Tom. Maybe though we
should have a note somewhere to the effect that you can't use VARIADIC
with these.

Perhaps such a note belongs hoisted into the functions-conditional
section of the manual, making a general observation that these things
are conditional *expressions* that may resemble functions, but in
particular, COALESCE, GREATEST, and LEAST cannot be called with
keyword VARIADIC and an array argument, as they could if they were
ordinary functions.




I'm going to mark this as rejected. Here's a possible doc patch


+1

--
-David
da...@pgmasters.net



Re: proposal: variadic argument support for least, greatest function

2019-03-11 Thread Andrew Dunstan

On 3/6/19 10:24 AM, Chapman Flack wrote:
> On 3/6/19 10:12 AM, Andrew Dunstan wrote:
>
>> Having reviewed the thread, I'm with Andres and Tom. Maybe though we
>> should have a note somewhere to the effect that you can't use VARIADIC
>> with these.
> Perhaps such a note belongs hoisted into the functions-conditional
> section of the manual, making a general observation that these things
> are conditional *expressions* that may resemble functions, but in
> particular, COALESCE, GREATEST, and LEAST cannot be called with
> keyword VARIADIC and an array argument, as they could if they were
> ordinary functions.
>


I'm going to mark this as rejected. Here's a possible doc patch


cheers


andrew


-- 
Andrew Dunstanhttps://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 03859a78ea..7fbcdfeae5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12481,6 +12481,15 @@ SELECT setval('foo', 42, false);Next nextval
   
 
+   
+
+ Although COALESCE, GREATEST, and
+ LEAST are syntactically similar to functions, they are
+ not strictly functions, and thus cannot be used with explicit
+ VARIADIC array arguments.
+
+   
+
   
CASE
 


Re: proposal: variadic argument support for least, greatest function

2019-03-06 Thread Pavel Stehule
st 6. 3. 2019 v 16:24 odesílatel Chapman Flack 
napsal:

> On 3/6/19 10:12 AM, Andrew Dunstan wrote:
>
> > Having reviewed the thread, I'm with Andres and Tom. Maybe though we
> > should have a note somewhere to the effect that you can't use VARIADIC
> > with these.
>
> Perhaps such a note belongs hoisted into the functions-conditional
> section of the manual, making a general observation that these things
> are conditional *expressions* that may resemble functions, but in
> particular, COALESCE, GREATEST, and LEAST cannot be called with
> keyword VARIADIC and an array argument, as they could if they were
> ordinary functions.
>

+1

Pavel


> Regards,
> -Chap
>


Re: proposal: variadic argument support for least, greatest function

2019-03-06 Thread Chapman Flack
On 3/6/19 10:12 AM, Andrew Dunstan wrote:

> Having reviewed the thread, I'm with Andres and Tom. Maybe though we
> should have a note somewhere to the effect that you can't use VARIADIC
> with these.

Perhaps such a note belongs hoisted into the functions-conditional
section of the manual, making a general observation that these things
are conditional *expressions* that may resemble functions, but in
particular, COALESCE, GREATEST, and LEAST cannot be called with
keyword VARIADIC and an array argument, as they could if they were
ordinary functions.

Regards,
-Chap



Re: proposal: variadic argument support for least, greatest function

2019-03-06 Thread Andrew Dunstan


On 3/4/19 9:39 AM, David Steele wrote:
> On 3/1/19 3:59 AM, Chapman Flack wrote:
>> The following review has been posted through the commitfest application:
>> make installcheck-world:  tested, passed
>> Implements feature:   tested, passed
>> Spec compliant:   not tested
>> Documentation:    tested, passed
>>
>> For completeness, I'll mark this reviewed again. It passes
>> installcheck-world, the latest patch addresses the suggestions from
>> me, and is improved on the code-structure matters that Tom pointed
>> out. I don't know if it will meet Tom's threshold for desirability
>> overall, but that sounds like a committer call at this point, so I'll
>> change it to RfC.
>
> Both committers who have looked at this patch (Tom, and Andres in his
> patch roundup [1]) recommend that it be rejected.
>
> If no committer steps up in the next week I think we should mark it as
> rejected.
>
>

Having reviewed the thread, I'm with Andres and Tom. Maybe though we
should have a note somewhere to the effect that you can't use VARIADIC
with these.


cheers


andrew

-- 
Andrew Dunstanhttps://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services




Re: Re: proposal: variadic argument support for least, greatest function

2019-03-04 Thread David Steele

On 3/1/19 3:59 AM, Chapman Flack wrote:

The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   tested, passed
Spec compliant:   not tested
Documentation:tested, passed

For completeness, I'll mark this reviewed again. It passes installcheck-world, 
the latest patch addresses the suggestions from me, and is improved on the 
code-structure matters that Tom pointed out. I don't know if it will meet Tom's 
threshold for desirability overall, but that sounds like a committer call at 
this point, so I'll change it to RfC.


Both committers who have looked at this patch (Tom, and Andres in his 
patch roundup [1]) recommend that it be rejected.


If no committer steps up in the next week I think we should mark it as 
rejected.


Regards,
--
-David
da...@pgmasters.net

[1] 
https://www.postgresql.org/message-id/20190214203752.t4hl574k6jlu4t25%40alap3.anarazel.de




Re: proposal: variadic argument support for least, greatest function

2019-02-28 Thread Chapman Flack
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   tested, passed
Spec compliant:   not tested
Documentation:tested, passed

For completeness, I'll mark this reviewed again. It passes installcheck-world, 
the latest patch addresses the suggestions from me, and is improved on the 
code-structure matters that Tom pointed out. I don't know if it will meet Tom's 
threshold for desirability overall, but that sounds like a committer call at 
this point, so I'll change it to RfC.

-Chap

The new status of this patch is: Ready for Committer


Re: proposal: variadic argument support for least, greatest function

2019-02-24 Thread Pavel Stehule
so 23. 2. 2019 v 20:23 odesílatel Chapman Flack 
napsal:

> On 02/23/19 13:35, Pavel Stehule wrote:
> > please, see, attached patch
>
> It is getting close, for my purposes. There is still this:
>
> >> Can the sentence added to the doc be changed to "These functions support
> >> passing parameters as an array after VARIADIC
> >> keyword."? That is, s/supports/support/ and s/a/an/. I've done that
> >> after a couple of recent patches, but it seems to be on springs.
>

fixed


>
>
> > I know so is important to understand to things, but nobody can understand
> > to all. And then it is nice, so the things just works
> >>
> >> The approach with more parsimony indoors would be to just create a few
> >> new ordinary functions, and add to the doc explaining why they are
> >> different, and that would be a patch only needing to touch a couple
> files.
> >>
> >> I have a feeling that the final decision on whether the indoor or
> outdoor
> >> parsimony matters more will be made by Tom, or another committer; I find
> >> myself seeing both sides, and not feeling insider-y enough myself to
> >> pick one.
> >
> > sure, every time it is commiter's decision.
>
>
> A part of me waits to see if another voice chimes in on the high-level
> want/don't-want question ... I think enough of the patch is ready for
> that question to be ripe, and if the answer is going to be "don't want"
> it would be ideal to know that before additional iterations of work on it.
>

sure

Regards

Pavel


> -Chap
>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..5e10124de9 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions support passing parameters as an array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..b1f3bc86de 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2811,6 +2811,10 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
 	MinMaxOp	operator = op->d.minmax.op;
 	int			off;
+	ArrayIterator array_iterator = NULL;
+	int			nelems;
+	bool		is_greatest;
+	bool		is_least;
 
 	/* set at initialization */
 	Assert(fcinfo->args[0].isnull == false);
@@ -2819,16 +2823,52 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
-	for (off = 0; off < op->d.minmax.nelems; off++)
+	is_least = operator == IS_LEAST || operator == IS_LEAST_VARIADIC;
+	is_greatest = operator == IS_GREATEST || operator == IS_GREATEST_VARIADIC;
+
+	if (IsVariadicMinMax(operator))
+	{
+		ArrayType  *arr;
+
+		/* result is null, when variadic argument is NULL */
+		if (nulls[0])
+			return;
+
+		/* prepare iterarator */
+		arr = DatumGetArrayTypeP(values[0]);
+		array_iterator = array_create_iterator(arr, 0, NULL);
+
+		nelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+	}
+	else
+		nelems = op->d.minmax.nelems;
+
+	for (off = 0; off < nelems; off++)
 	{
+		Datum	value;
+		bool	isnull;
+
+		if (array_iterator)
+		{
+			bool has_data PG_USED_FOR_ASSERTS_ONLY;
+
+			has_data = array_iterate(array_iterator, , );
+			Assert(has_data);
+		}
+		else
+		{
+			value = values[off];
+			isnull = nulls[off];
+		}
+
 		/* ignore NULL inputs */
-		if (nulls[off])
+		if (isnull)
 			continue;
 
 		if (*op->resnull)
 		{
 			/* first nonnull input, adopt value */
-			*op->resvalue = values[off];
+			*op->resvalue = value;
 			*op->resnull = false;
 		}
 		else
@@ -2837,19 +2877,23 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 
 			/* apply comparison function */
 			fcinfo->args[0].value = *op->resvalue;
-			fcinfo->args[1].value = values[off];
+			fcinfo->args[1].value = value;
 
 			fcinfo->isnull = false;
 			cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
 			if (fcinfo->isnull) /* probably should not happen */
 continue;
 
-			if (cmpresult > 0 && operator == IS_LEAST)
-*op->resvalue = values[off];
-			else if (cmpresult < 0 && operator == IS_GREATEST)
-*op->resvalue = values[off];
+			if (cmpresult > 0 && is_least)
+*op->resvalue = value;
+			else if (cmpresult < 0 && is_greatest)
+*op->resvalue = value;
 		}
 	}
+
+	/* release iterator */
+	if (array_iterator)
+		array_free_iterator(array_iterator);
 }
 
 /*
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 8ed30c011a..efabaa0046 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -465,7 +465,8 @@ exprTypmod(const Node *expr)
 int32		typmod;
 ListCell   *arg;
 
-if (exprType((Node *) 

Re: proposal: variadic argument support for least, greatest function

2019-02-23 Thread Chapman Flack
On 02/23/19 13:35, Pavel Stehule wrote:
> please, see, attached patch

It is getting close, for my purposes. There is still this:

>> Can the sentence added to the doc be changed to "These functions support
>> passing parameters as an array after VARIADIC
>> keyword."? That is, s/supports/support/ and s/a/an/. I've done that
>> after a couple of recent patches, but it seems to be on springs.



> I know so is important to understand to things, but nobody can understand
> to all. And then it is nice, so the things just works
>>
>> The approach with more parsimony indoors would be to just create a few
>> new ordinary functions, and add to the doc explaining why they are
>> different, and that would be a patch only needing to touch a couple files.
>>
>> I have a feeling that the final decision on whether the indoor or outdoor
>> parsimony matters more will be made by Tom, or another committer; I find
>> myself seeing both sides, and not feeling insider-y enough myself to
>> pick one.
> 
> sure, every time it is commiter's decision.


A part of me waits to see if another voice chimes in on the high-level
want/don't-want question ... I think enough of the patch is ready for
that question to be ripe, and if the answer is going to be "don't want"
it would be ideal to know that before additional iterations of work on it.

-Chap



Re: proposal: variadic argument support for least, greatest function

2019-02-23 Thread Pavel Stehule
so 23. 2. 2019 v 18:28 odesílatel Chapman Flack 
napsal:

> On 02/23/19 01:22, Pavel Stehule wrote:
> > so 23. 2. 2019 v 4:50 odesílatel Chapman Flack 
> > napsal:
>
> >> In transformMinMaxExpr:
> >> The assignment of funcname doesn't look right.
>
> ... it still doesn't.
>

fixed


> >> Two new errors are elogs. ...
> >> I am not sure if there is a way for user input to trigger the first one.
> >> Perhaps it can stay an elog if not. In any case, s/to
> >> determinate/determine/.
> >>
> >
> > It is +/- internal error and usually should not be touched - so there I
> > prefer elog. I fix message
>
> ... still needs s/to //.
>

fixed


> Can the sentence added to the doc be changed to "These functions support
> passing parameters as an array after VARIADIC keyword."?
> That is, s/supports/support/ and s/a/an/. I've done that after a couple of
> recent patches, but it seems to be on springs.
>
> > What about using macros?
>
> Meh ... the macros look nicer, but still rely just as much on the compiler
> to hoist the tests out of the loop. I suppose it probably can.
>

reverted, I use a variables

>
> I wouldn't have thought it necessary to change the switch statements in
> FigureColnameInternal or get_rule_expr ... cases with multiple labels are
> seen often enough, and it's probably hard to do better.
>
>
> Taking a step back ...
>
>
> All of this still begs Tom's question about whether array_greatest/
> array_least would be preferable.
>
> I understand Pavel's point:
>
> >> I am not against these functions, but these functions doesn't solve a
> >> confusing of some users, so LEAST, GREATEST looks like variadic
> >> functions, but it doesn't allow VARIADIC parameter.
>
> but, to advocate the other side for a moment, perhaps that could be viewed
> as more of a documentation problem.
>
> At bottom, the confusion potential that concerns Pavel exists because
> these things look like variadic functions, and the manual calls them
> "the GREATEST and LEAST functions", but they won't accept a VARIADIC array
> parameter as a genuine variadic function would.
>
> But that's hardly the only way these differ from normal functions.
> You can't find them in pg_proc or call them through fmgr. In fact, they
> share these non-function properties with all of their siblings in the
> functions-conditional section of the manual. (Arguably, if GREATEST and
> LEAST end up taking a VARIADIC array parameter, COALESCE will be wanting
> one next. And indeed, there doesn't seem to be an existing
> array_firstnonnull function for that job, either.) And these "functions"
> have special, type-unifying argument rules (already documented in
> typeconv-union-case), late argument evaluation in the case of COALESCE,
> and so on.
>
> In other words, any effort to make these animals act more like functions
> will be necessarily incomplete, and differences will remain.
>
> Maybe the confusion-potential could be fixed by having one more sentence
> at the top of the whole functions-conditional section, saying "Some of
> these resemble functions, but are better viewed as function-like
> expressions, with special rules for their argument lists." Then the section
> for GREATEST/LEAST could have a "see also" for array_greatest/array_least,
> the COALESCE section a "see also" for array_firstnonnull, and those simple
> functions could be written.
>
> The special rules for these constructs don't really buy anything for the
> array-argument flavors: you can't pass in an array with heterogeneous
> types or late-evaluated values anyway, so ordinary functions would suffice.
>
> From the outside, it would look tidy and parsimonious to just have
> GREATEST(VARIADIC...)/LEAST(VARIADIC...)/COALESCE(VARIADIC...) and have
> just one set of "function" names to remember, rather than separate
> array_* variants. But the cost of that tidiness from the outside is an
> implementation that has to frob half a dozen source files on the inside.
>

This is goal of this small patch - do life little bit more easier and
little bit more consistent.

It is very small patch without risks or slowdowns. So I expect the cost of
this patch is small. Just it is small step forward to users.

I wrote "greatest", "least" support before I wrote variadic functions
support. If I wrote it in different order, probably, greatest, least
functions was pg_proc based. On second hand, the limitation of pg_proc
functions was motivation for variadic function support.

With my experience, I am not sure if better documentation does things
better. For some kind of users some smart magic is important. They don't
want to see implementation details.

In my car, i lost hope to understand completely to engine. I am not sure if
users should to know so we have three kind of functions - a) pg_proc based
functions, b) parser based functions (and looks like functions), c) parser
based functions (and looks like constant).

I know so is important to understand to things, but nobody can understand
to all. And then it is 

Re: proposal: variadic argument support for least, greatest function

2019-02-23 Thread Chapman Flack
On 02/23/19 01:22, Pavel Stehule wrote:
> so 23. 2. 2019 v 4:50 odesílatel Chapman Flack 
> napsal:

>> In transformMinMaxExpr:
>> The assignment of funcname doesn't look right.

... it still doesn't.

>> Two new errors are elogs. ...
>> I am not sure if there is a way for user input to trigger the first one.
>> Perhaps it can stay an elog if not. In any case, s/to
>> determinate/determine/.
>>
> 
> It is +/- internal error and usually should not be touched - so there I
> prefer elog. I fix message

... still needs s/to //.

Can the sentence added to the doc be changed to "These functions support
passing parameters as an array after VARIADIC keyword."?
That is, s/supports/support/ and s/a/an/. I've done that after a couple of
recent patches, but it seems to be on springs.

> What about using macros?

Meh ... the macros look nicer, but still rely just as much on the compiler
to hoist the tests out of the loop. I suppose it probably can.

I wouldn't have thought it necessary to change the switch statements in
FigureColnameInternal or get_rule_expr ... cases with multiple labels are
seen often enough, and it's probably hard to do better.


Taking a step back ...


All of this still begs Tom's question about whether array_greatest/
array_least would be preferable.

I understand Pavel's point:

>> I am not against these functions, but these functions doesn't solve a
>> confusing of some users, so LEAST, GREATEST looks like variadic
>> functions, but it doesn't allow VARIADIC parameter.

but, to advocate the other side for a moment, perhaps that could be viewed
as more of a documentation problem.

At bottom, the confusion potential that concerns Pavel exists because
these things look like variadic functions, and the manual calls them
"the GREATEST and LEAST functions", but they won't accept a VARIADIC array
parameter as a genuine variadic function would.

But that's hardly the only way these differ from normal functions.
You can't find them in pg_proc or call them through fmgr. In fact, they
share these non-function properties with all of their siblings in the
functions-conditional section of the manual. (Arguably, if GREATEST and
LEAST end up taking a VARIADIC array parameter, COALESCE will be wanting
one next. And indeed, there doesn't seem to be an existing
array_firstnonnull function for that job, either.) And these "functions"
have special, type-unifying argument rules (already documented in
typeconv-union-case), late argument evaluation in the case of COALESCE,
and so on.

In other words, any effort to make these animals act more like functions
will be necessarily incomplete, and differences will remain.

Maybe the confusion-potential could be fixed by having one more sentence
at the top of the whole functions-conditional section, saying "Some of
these resemble functions, but are better viewed as function-like
expressions, with special rules for their argument lists." Then the section
for GREATEST/LEAST could have a "see also" for array_greatest/array_least,
the COALESCE section a "see also" for array_firstnonnull, and those simple
functions could be written.

The special rules for these constructs don't really buy anything for the
array-argument flavors: you can't pass in an array with heterogeneous
types or late-evaluated values anyway, so ordinary functions would suffice.

>From the outside, it would look tidy and parsimonious to just have
GREATEST(VARIADIC...)/LEAST(VARIADIC...)/COALESCE(VARIADIC...) and have
just one set of "function" names to remember, rather than separate
array_* variants. But the cost of that tidiness from the outside is an
implementation that has to frob half a dozen source files on the inside.

The approach with more parsimony indoors would be to just create a few
new ordinary functions, and add to the doc explaining why they are
different, and that would be a patch only needing to touch a couple files.

I have a feeling that the final decision on whether the indoor or outdoor
parsimony matters more will be made by Tom, or another committer; I find
myself seeing both sides, and not feeling insider-y enough myself to
pick one.

-Chap



Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Pavel Stehule
so 23. 2. 2019 v 4:50 odesílatel Chapman Flack 
napsal:

> The following review has been posted through the commitfest application:
> make installcheck-world:  tested, passed
> Implements feature:   tested, passed
> Spec compliant:   not tested
> Documentation:tested, passed
>
> The latest patch provides the same functionality without growing the size
> of struct ExprEvalStep, and without using the presence/absence of
> args/variadic_args to distinguish the cases. It now uses the args field
> consistently, and distinguishes the cases with new op constants,
> IS_GREATEST_VARIADIC and IS_LEAST_VARIADIC, assigned at parse time. I
> concede Tom's points about the comparative wartiness of the former patch.
>
> I'll change to WoA, though, for a few loose ends:
>
> In transformMinMaxExpr:
> The assignment of funcname doesn't look right.
> Two new errors are elogs. If they can be caused by user input (I'm sure
> the second one can), should they not be ereports?
> In fact, I think the second one should copy the equivalent one from
> parse_func.c:
>
> > ereport(ERROR,
> > (errcode(ERRCODE_DATATYPE_MISMATCH),
> > errmsg("VARIADIC argument must be an array"),
> > parser_errposition(pstate,
> > exprLocation((Node *) llast(fargs);
>
> ... both for consistency of the message, and so (I assume) it can use the
> existing translations for that message string.
>

good idea, done


> I am not sure if there is a way for user input to trigger the first one.
> Perhaps it can stay an elog if not. In any case, s/to
> determinate/determine/.
>

It is +/- internal error and usually should not be touched - so there I
prefer elog. I fix message


>
> In EvalExecMinMax:
>
> +   if (cmpresult > 0 &&
> +   (operator == IS_LEAST || operator ==
> IS_LEAST_VARIADIC))
> +   *op->resvalue = value;
> +   else if (cmpresult < 0 &&
> +(operator == IS_GREATEST ||
> operator == IS_GREATEST_VARIADIC))
>
> would it make sense to just compute a boolean isleast before entering the
> loop, to get simply (cmpresult > 0 && isleast) or (cmpresult < 0 &&
> !isleast) inside the loop? I'm unsure whether to assume the compiler will
> see that opportunity.
>

I am have not strong opinion about it. Personally I dislike a two variables
- but any discussion is partially about premature optimization. What about
using macros?



> Regards,
> -Chap
>
> The new status of this patch is: Waiting on Author
>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions supports passing parameters as a array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..8ac4628ec1 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2811,6 +2811,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
 	MinMaxOp	operator = op->d.minmax.op;
 	int			off;
+	ArrayIterator array_iterator = NULL;
+	int			nelems;
 
 	/* set at initialization */
 	Assert(fcinfo->args[0].isnull == false);
@@ -2819,16 +2821,49 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
-	for (off = 0; off < op->d.minmax.nelems; off++)
+	if (IsMinMaxVariadic(operator))
 	{
+		ArrayType  *arr;
+
+		/* result is null, when variadic argument is NULL */
+		if (nulls[0])
+			return;
+
+		/* prepare iterarator */
+		arr = DatumGetArrayTypeP(values[0]);
+		array_iterator = array_create_iterator(arr, 0, NULL);
+
+		nelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+	}
+	else
+		nelems = op->d.minmax.nelems;
+
+	for (off = 0; off < nelems; off++)
+	{
+		Datum	value;
+		bool	isnull;
+
+		if (array_iterator)
+		{
+			bool has_data PG_USED_FOR_ASSERTS_ONLY;
+
+			has_data = array_iterate(array_iterator, , );
+			Assert(has_data);
+		}
+		else
+		{
+			value = values[off];
+			isnull = nulls[off];
+		}
+
 		/* ignore NULL inputs */
-		if (nulls[off])
+		if (isnull)
 			continue;
 
 		if (*op->resnull)
 		{
 			/* first nonnull input, adopt value */
-			*op->resvalue = values[off];
+			*op->resvalue = value;
 			*op->resnull = false;
 		}
 		else
@@ -2837,19 +2872,23 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 
 			/* apply comparison function */
 			fcinfo->args[0].value = *op->resvalue;
-			fcinfo->args[1].value = values[off];
+			fcinfo->args[1].value 

Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Chapman Flack
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   tested, passed
Spec compliant:   not tested
Documentation:tested, passed

The latest patch provides the same functionality without growing the size of 
struct ExprEvalStep, and without using the presence/absence of 
args/variadic_args to distinguish the cases. It now uses the args field 
consistently, and distinguishes the cases with new op constants, 
IS_GREATEST_VARIADIC and IS_LEAST_VARIADIC, assigned at parse time. I concede 
Tom's points about the comparative wartiness of the former patch.

I'll change to WoA, though, for a few loose ends:

In transformMinMaxExpr:
The assignment of funcname doesn't look right.
Two new errors are elogs. If they can be caused by user input (I'm sure the 
second one can), should they not be ereports?
In fact, I think the second one should copy the equivalent one from 
parse_func.c:

> ereport(ERROR,
> (errcode(ERRCODE_DATATYPE_MISMATCH),
> errmsg("VARIADIC argument must be an array"),
> parser_errposition(pstate,
> exprLocation((Node *) llast(fargs);

... both for consistency of the message, and so (I assume) it can use the 
existing translations for that message string.

I am not sure if there is a way for user input to trigger the first one. 
Perhaps it can stay an elog if not. In any case, s/to determinate/determine/.

In EvalExecMinMax:

+   if (cmpresult > 0 && 
+   (operator == IS_LEAST || operator == 
IS_LEAST_VARIADIC))
+   *op->resvalue = value;
+   else if (cmpresult < 0 &&
+(operator == IS_GREATEST || operator 
== IS_GREATEST_VARIADIC))

would it make sense to just compute a boolean isleast before entering the loop, 
to get simply (cmpresult > 0 && isleast) or (cmpresult < 0 && !isleast) inside 
the loop? I'm unsure whether to assume the compiler will see that opportunity.

Regards,
-Chap

The new status of this patch is: Waiting on Author


Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Chapman Flack
On 02/22/19 19:31, Chapman Flack wrote:
> minmax_variadic-20190222-3.patch same as -2 but for doc grammar fix
> (same fix made in minmax_variadic-20190221b.patch).

and naturally I didn't attach it.

-Chap
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions support passing parameters as an array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..2b98f7e820 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2811,6 +2811,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
 	MinMaxOp	operator = op->d.minmax.op;
 	int			off;
+	ArrayIterator array_iterator = NULL;
+	int			nelems;
 
 	/* set at initialization */
 	Assert(fcinfo->args[0].isnull == false);
@@ -2819,16 +2821,49 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
-	for (off = 0; off < op->d.minmax.nelems; off++)
+	if (IsVariadicMinMax(operator))
 	{
+		ArrayType  *arr;
+
+		/* result is null, when variadic argument is NULL */
+		if (nulls[0])
+			return;
+
+		/* prepare iterarator */
+		arr = DatumGetArrayTypeP(values[0]);
+		array_iterator = array_create_iterator(arr, 0, NULL);
+
+		nelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+	}
+	else
+		nelems = op->d.minmax.nelems;
+
+	for (off = 0; off < nelems; off++)
+	{
+		Datum	value;
+		bool	isnull;
+
+		if (array_iterator)
+		{
+			bool has_data PG_USED_FOR_ASSERTS_ONLY;
+
+			has_data = array_iterate(array_iterator, , );
+			Assert(has_data);
+		}
+		else
+		{
+			value = values[off];
+			isnull = nulls[off];
+		}
+
 		/* ignore NULL inputs */
-		if (nulls[off])
+		if (isnull)
 			continue;
 
 		if (*op->resnull)
 		{
 			/* first nonnull input, adopt value */
-			*op->resvalue = values[off];
+			*op->resvalue = value;
 			*op->resnull = false;
 		}
 		else
@@ -2837,19 +2872,25 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 
 			/* apply comparison function */
 			fcinfo->args[0].value = *op->resvalue;
-			fcinfo->args[1].value = values[off];
+			fcinfo->args[1].value = value;
 
 			fcinfo->isnull = false;
 			cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
 			if (fcinfo->isnull) /* probably should not happen */
 continue;
 
-			if (cmpresult > 0 && operator == IS_LEAST)
-*op->resvalue = values[off];
-			else if (cmpresult < 0 && operator == IS_GREATEST)
-*op->resvalue = values[off];
+			if (cmpresult > 0 && 
+(operator == IS_LEAST || operator == IS_LEAST_VARIADIC))
+*op->resvalue = value;
+			else if (cmpresult < 0 &&
+	 (operator == IS_GREATEST || operator == IS_GREATEST_VARIADIC))
+*op->resvalue = value;
 		}
 	}
+
+	/* release iterator */
+	if (array_iterator)
+		array_free_iterator(array_iterator);
 }
 
 /*
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 8ed30c011a..efabaa0046 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -465,7 +465,8 @@ exprTypmod(const Node *expr)
 int32		typmod;
 ListCell   *arg;
 
-if (exprType((Node *) linitial(mexpr->args)) != minmaxtype)
+if (!IsVariadicMinMax(mexpr->op) &&
+		exprType((Node *) linitial(mexpr->args)) != minmaxtype)
 	return -1;
 typmod = exprTypmod((Node *) linitial(mexpr->args));
 if (typmod < 0)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a68f78e0e0..65f44a8df6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13803,6 +13803,22 @@ func_expr_common_subexpr:
 	v->location = @1;
 	$$ = (Node *)v;
 }
+			| GREATEST '(' VARIADIC a_expr ')'
+{
+	MinMaxExpr *v = makeNode(MinMaxExpr);
+	v->args = list_make1($4);
+	v->op = IS_GREATEST_VARIADIC;
+	v->location = @1;
+	$$ = (Node *)v;
+}
+			| LEAST '(' VARIADIC a_expr ')'
+{
+	MinMaxExpr *v = makeNode(MinMaxExpr);
+	v->args = list_make1($4);
+	v->op = IS_LEAST_VARIADIC;
+	v->location = @1;
+	$$ = (Node *)v;
+}
 			| XMLCONCAT '(' expr_list ')'
 {
 	$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index e559353529..d739582ba0 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2276,22 +2276,43 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
 		newargs = lappend(newargs, newe);
 	}
 
-	newm->minmaxtype = 

Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Chapman Flack
On 02/22/19 14:57, Pavel Stehule wrote:
> I am sending second variant (little bit longer, but the main code is not
> repeated)

minmax_variadic-20190222-3.patch same as -2 but for doc grammar fix
(same fix made in minmax_variadic-20190221b.patch).

Regards,
-Chap



Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Pavel Stehule
pá 22. 2. 2019 v 13:42 odesílatel Pavel Stehule 
napsal:

> Hi
>
> čt 21. 2. 2019 v 22:05 odesílatel Tom Lane  napsal:
>
>> Pavel Stehule  writes:
>> > čt 21. 2. 2019 v 3:20 odesílatel Chapman Flack 
>> > napsal:
>> >> I am not sure I have an answer to the objections being raised on
>> grounds
>> >> of taste. To me, it's persuasive that GREATEST and LEAST are described
>> in
>> >> the docco as functions, they are used much like variadic functions, and
>> >> this patch allows them to be used in the ways you would expect variadic
>> >> functions to be usable.
>>
>> > I wrote doc (just one sentence) and minimal test. Both can be enhanced.
>>
>> I remain of the opinion that this patch is a mess.
>>
>> I don't share Pavel's opinion that this is a clean user API, though
>> I'll grant that others might have different opinions on that.
>> I could hold my nose and overlook that if it led to a clean internal
>> implementation.  But it doesn't: this patch just bolts a huge,
>> undocumented wart onto the side of MinMaxExpr.  (The arguments are
>> in the args field, except when they aren't?  And everyplace that
>> deals with MinMaxExpr needs to know that, as well as the fact that
>> the semantics are totally different?  Ick.)
>>
>
> fixed
>
>
>> An example of the lack of care here is that the change in struct
>> ExprEvalStep breaks that struct's size constraint:
>>
>>  * Inline data for the operation.  Inline data is faster to access,
>> but
>>  * also bloats the size of all instructions.  The union should be
>> kept to
>>  * no more than 40 bytes on 64-bit systems (so that the entire struct
>> is
>>  * no more than 64 bytes, a single cacheline on common systems).
>>
>>
> fixed
>
>
>> Andres is going to be quite displeased if that gets committed ;-).
>>
>
> I hope so I solved all your objections. Now, the patch is really reduced.
>
>
>
>> I still say we should reject this and invent array_greatest/array_least
>> functions instead.
>>
>
> I am not against these functions, but these functions doesn't solve a
> confusing of some users, so LEAST, GREATEST looks like variadic functions,
> but it doesn't allow VARIADIC parameter.
>
> Comments, notes?
>

I am sending second variant (little bit longer, but the main code is not
repeated)

regards

Pavel


>
>
>> regards, tom lane
>>
>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions supports passing parameters as a array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..2b98f7e820 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2811,6 +2811,8 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	FunctionCallInfo fcinfo = op->d.minmax.fcinfo_data;
 	MinMaxOp	operator = op->d.minmax.op;
 	int			off;
+	ArrayIterator array_iterator = NULL;
+	int			nelems;
 
 	/* set at initialization */
 	Assert(fcinfo->args[0].isnull == false);
@@ -2819,16 +2821,49 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
-	for (off = 0; off < op->d.minmax.nelems; off++)
+	if (IsVariadicMinMax(operator))
 	{
+		ArrayType  *arr;
+
+		/* result is null, when variadic argument is NULL */
+		if (nulls[0])
+			return;
+
+		/* prepare iterarator */
+		arr = DatumGetArrayTypeP(values[0]);
+		array_iterator = array_create_iterator(arr, 0, NULL);
+
+		nelems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+	}
+	else
+		nelems = op->d.minmax.nelems;
+
+	for (off = 0; off < nelems; off++)
+	{
+		Datum	value;
+		bool	isnull;
+
+		if (array_iterator)
+		{
+			bool has_data PG_USED_FOR_ASSERTS_ONLY;
+
+			has_data = array_iterate(array_iterator, , );
+			Assert(has_data);
+		}
+		else
+		{
+			value = values[off];
+			isnull = nulls[off];
+		}
+
 		/* ignore NULL inputs */
-		if (nulls[off])
+		if (isnull)
 			continue;
 
 		if (*op->resnull)
 		{
 			/* first nonnull input, adopt value */
-			*op->resvalue = values[off];
+			*op->resvalue = value;
 			*op->resnull = false;
 		}
 		else
@@ -2837,19 +2872,25 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 
 			/* apply comparison function */
 			fcinfo->args[0].value = *op->resvalue;
-			fcinfo->args[1].value = values[off];
+			fcinfo->args[1].value = value;
 
 			fcinfo->isnull = false;
 			cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
 			if (fcinfo->isnull) /* probably should not happen */
 continue;
 
-			if (cmpresult > 0 && operator == IS_LEAST)
-

Re: proposal: variadic argument support for least, greatest function

2019-02-22 Thread Pavel Stehule
Hi

čt 21. 2. 2019 v 22:05 odesílatel Tom Lane  napsal:

> Pavel Stehule  writes:
> > čt 21. 2. 2019 v 3:20 odesílatel Chapman Flack 
> > napsal:
> >> I am not sure I have an answer to the objections being raised on grounds
> >> of taste. To me, it's persuasive that GREATEST and LEAST are described
> in
> >> the docco as functions, they are used much like variadic functions, and
> >> this patch allows them to be used in the ways you would expect variadic
> >> functions to be usable.
>
> > I wrote doc (just one sentence) and minimal test. Both can be enhanced.
>
> I remain of the opinion that this patch is a mess.
>
> I don't share Pavel's opinion that this is a clean user API, though
> I'll grant that others might have different opinions on that.
> I could hold my nose and overlook that if it led to a clean internal
> implementation.  But it doesn't: this patch just bolts a huge,
> undocumented wart onto the side of MinMaxExpr.  (The arguments are
> in the args field, except when they aren't?  And everyplace that
> deals with MinMaxExpr needs to know that, as well as the fact that
> the semantics are totally different?  Ick.)
>

fixed


> An example of the lack of care here is that the change in struct
> ExprEvalStep breaks that struct's size constraint:
>
>  * Inline data for the operation.  Inline data is faster to access, but
>  * also bloats the size of all instructions.  The union should be kept
> to
>  * no more than 40 bytes on 64-bit systems (so that the entire struct
> is
>  * no more than 64 bytes, a single cacheline on common systems).
>
>
fixed


> Andres is going to be quite displeased if that gets committed ;-).
>

I hope so I solved all your objections. Now, the patch is really reduced.



> I still say we should reject this and invent array_greatest/array_least
> functions instead.
>

I am not against these functions, but these functions doesn't solve a
confusing of some users, so LEAST, GREATEST looks like variadic functions,
but it doesn't allow VARIADIC parameter.

Comments, notes?



> regards, tom lane
>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions supports passing parameters as a array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..418aca9c84 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2819,6 +2819,55 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
+	if (IsVariadicMinMax(operator))
+	{
+		ArrayIterator array_iterator;
+		ArrayType  *arr;
+		Datum	value;
+		bool	isnull;
+
+		if (nulls[0])
+			return;
+
+		arr = DatumGetArrayTypeP(values[0]);
+
+		array_iterator = array_create_iterator(arr, 0, NULL);
+		while (array_iterate(array_iterator, , ))
+		{
+			if (isnull)
+continue;
+
+			if (*op->resnull)
+			{
+/* first nonnull input */
+*op->resvalue = value;
+*op->resnull = false;
+			}
+			else
+			{
+int			cmpresult;
+
+Assert(fcinfo->nargs == 2);
+
+/* apply comparison function */
+fcinfo->args[0].value = *op->resvalue;
+fcinfo->args[1].value = value;
+
+fcinfo->isnull = false;
+cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
+if (fcinfo->isnull) /* probably should not happen */
+	continue;
+
+if (cmpresult > 0 && operator == IS_LEAST_VARIADIC)
+	*op->resvalue = value;
+else if (cmpresult < 0 && operator == IS_GREATEST_VARIADIC)
+	*op->resvalue = value;
+			}
+		}
+
+		return;
+	}
+
 	for (off = 0; off < op->d.minmax.nelems; off++)
 	{
 		/* ignore NULL inputs */
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 8ed30c011a..efabaa0046 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -465,7 +465,8 @@ exprTypmod(const Node *expr)
 int32		typmod;
 ListCell   *arg;
 
-if (exprType((Node *) linitial(mexpr->args)) != minmaxtype)
+if (!IsVariadicMinMax(mexpr->op) &&
+		exprType((Node *) linitial(mexpr->args)) != minmaxtype)
 	return -1;
 typmod = exprTypmod((Node *) linitial(mexpr->args));
 if (typmod < 0)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a68f78e0e0..65f44a8df6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -13803,6 +13803,22 @@ func_expr_common_subexpr:
 	v->location = @1;
 	$$ = (Node *)v;
 }
+			| GREATEST '(' VARIADIC a_expr ')'
+{
+	

Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread Chapman Flack
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   tested, passed
Spec compliant:   not tested
Documentation:tested, passed

On 02/21/19 16:04, Tom Lane wrote:
> Pavel Stehule  writes:
>> I wrote doc (just one sentence) and minimal test. Both can be enhanced.

* dutifully submits review saying latest patch passes installcheck-world and 
has tests and docs, could be RfC

> I still say we should reject this and invent array_greatest/array_least
> functions instead.

* reflects on own pay grade, wanders off in search of other patch to review

The new status of this patch is: Ready for Committer


Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread Chapman Flack
On 02/21/19 11:31, Pavel Stehule wrote:
> I wrote doc (just one sentence) and minimal test. Both can be enhanced.

Attaching minmax_variadic-20190221b.patch, identical but for
s/supports/support/ and s/a/an/ in the doc.

Regards,
-Chap
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions support passing parameters as an array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index db3777d15e..01d7f0e02c 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1854,13 +1854,18 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_MinMaxExpr:
 			{
 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
-int			nelems = list_length(minmaxexpr->args);
+int			nelems;
 TypeCacheEntry *typentry;
 FmgrInfo   *finfo;
 FunctionCallInfo fcinfo;
 ListCell   *lc;
 int			off;
 
+if (minmaxexpr->args)
+	nelems = list_length(minmaxexpr->args);
+else
+	nelems = 1;
+
 /* Look up the btree comparison function for the datatype */
 typentry = lookup_type_cache(minmaxexpr->minmaxtype,
 			 TYPECACHE_CMP_PROC);
@@ -1897,16 +1902,29 @@ ExecInitExprRec(Expr *node, ExprState *state,
 scratch.d.minmax.finfo = finfo;
 scratch.d.minmax.fcinfo_data = fcinfo;
 
-/* evaluate expressions into minmax->values/nulls */
-off = 0;
-foreach(lc, minmaxexpr->args)
+if (minmaxexpr->args)
 {
-	Expr	   *e = (Expr *) lfirst(lc);
+	scratch.d.minmax.variadic_arg = false;
 
-	ExecInitExprRec(e, state,
-	[off],
-	[off]);
-	off++;
+	/* evaluate expressions into minmax->values/nulls */
+	off = 0;
+	foreach(lc, minmaxexpr->args)
+	{
+		Expr	   *e = (Expr *) lfirst(lc);
+
+		ExecInitExprRec(e, state,
+		[off],
+		[off]);
+		off++;
+	}
+}
+else
+{
+	scratch.d.minmax.variadic_arg = true;
+
+	ExecInitExprRec(minmaxexpr->variadic_arg, state,
+		[0],
+		[0]);
 }
 
 /* and push the final comparison */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..748c950885 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2819,6 +2819,55 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
+	if (op->d.minmax.variadic_arg)
+	{
+		ArrayIterator array_iterator;
+		ArrayType  *arr;
+		Datum	value;
+		bool	isnull;
+
+		if (nulls[0])
+			return;
+
+		arr = DatumGetArrayTypeP(values[0]);
+
+		array_iterator = array_create_iterator(arr, 0, NULL);
+		while (array_iterate(array_iterator, , ))
+		{
+			if (isnull)
+continue;
+
+			if (*op->resnull)
+			{
+/* first nonnull input */
+*op->resvalue = value;
+*op->resnull = false;
+			}
+			else
+			{
+int			cmpresult;
+
+Assert(fcinfo->nargs == 2);
+
+/* apply comparison function */
+fcinfo->args[0].value = *op->resvalue;
+fcinfo->args[1].value = value;
+
+fcinfo->isnull = false;
+cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
+if (fcinfo->isnull) /* probably should not happen */
+	continue;
+
+if (cmpresult > 0 && operator == IS_LEAST)
+	*op->resvalue = value;
+else if (cmpresult < 0 && operator == IS_GREATEST)
+	*op->resvalue = value;
+			}
+		}
+
+		return;
+	}
+
 	for (off = 0; off < op->d.minmax.nelems; off++)
 	{
 		/* ignore NULL inputs */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e15724bb0e..e8ad89799f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1942,6 +1942,7 @@ _copyMinMaxExpr(const MinMaxExpr *from)
 	COPY_SCALAR_FIELD(inputcollid);
 	COPY_SCALAR_FIELD(op);
 	COPY_NODE_FIELD(args);
+	COPY_NODE_FIELD(variadic_arg);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 31499eb798..6623c7800d 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -635,6 +635,7 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
 	COMPARE_SCALAR_FIELD(inputcollid);
 	COMPARE_SCALAR_FIELD(op);
 	COMPARE_NODE_FIELD(args);
+	COMPARE_NODE_FIELD(variadic_arg);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 8ed30c011a..52fcf8d9b0 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ 

Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread Tom Lane
David Fetter  writes:
> On Thu, Feb 21, 2019 at 04:04:41PM -0500, Tom Lane wrote:
>> I still say we should reject this and invent array_greatest/array_least
>> functions instead.

> Might other array_* functions of this type be in scope for this patch?

Uh ... no, I wouldn't expect that.  Why would we insist on more
functionality than is there now?  (I'm only arguing about how we
present the functionality, not what it does.)

regards, tom lane



Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread David Fetter
On Thu, Feb 21, 2019 at 04:04:41PM -0500, Tom Lane wrote:
> I still say we should reject this and invent array_greatest/array_least
> functions instead.

Might other array_* functions of this type be in scope for this patch?

Best,
David.
-- 
David Fetter  http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate



Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread Tom Lane
Pavel Stehule  writes:
> čt 21. 2. 2019 v 3:20 odesílatel Chapman Flack 
> napsal:
>> I am not sure I have an answer to the objections being raised on grounds
>> of taste. To me, it's persuasive that GREATEST and LEAST are described in
>> the docco as functions, they are used much like variadic functions, and
>> this patch allows them to be used in the ways you would expect variadic
>> functions to be usable.

> I wrote doc (just one sentence) and minimal test. Both can be enhanced.

I remain of the opinion that this patch is a mess.

I don't share Pavel's opinion that this is a clean user API, though
I'll grant that others might have different opinions on that.
I could hold my nose and overlook that if it led to a clean internal
implementation.  But it doesn't: this patch just bolts a huge,
undocumented wart onto the side of MinMaxExpr.  (The arguments are
in the args field, except when they aren't?  And everyplace that
deals with MinMaxExpr needs to know that, as well as the fact that
the semantics are totally different?  Ick.)

An example of the lack of care here is that the change in struct
ExprEvalStep breaks that struct's size constraint:

 * Inline data for the operation.  Inline data is faster to access, but
 * also bloats the size of all instructions.  The union should be kept to
 * no more than 40 bytes on 64-bit systems (so that the entire struct is
 * no more than 64 bytes, a single cacheline on common systems).

Andres is going to be quite displeased if that gets committed ;-).

I still say we should reject this and invent array_greatest/array_least
functions instead.

regards, tom lane



Re: proposal: variadic argument support for least, greatest function

2019-02-21 Thread Pavel Stehule
Hi

čt 21. 2. 2019 v 3:20 odesílatel Chapman Flack 
napsal:

> The following review has been posted through the commitfest application:
> make installcheck-world:  tested, passed
> Implements feature:   tested, passed
> Spec compliant:   not tested
> Documentation:not tested
>
> Latest patch passes installcheck-world as of d26a810 and does what it sets
> out to do.
>
> I am not sure I have an answer to the objections being raised on grounds
> of taste. To me, it's persuasive that GREATEST and LEAST are described in
> the docco as functions, they are used much like variadic functions, and
> this patch allows them to be used in the ways you would expect variadic
> functions to be usable.
>
> But as to technical readiness, this builds and passes installcheck-world.
> The functions behave as expected (and return null if passed an empty array,
> or an array containing only nulls, or variadic null::foo[]).
>
> Still no corresponding regression tests or doc.
>
> The new status of this patch is: Waiting on Author
>

I wrote doc (just one sentence) and minimal test. Both can be enhanced.

Regards

Pavel
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 86ff4e5c9e..aa4e80cca7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12679,6 +12679,12 @@ SELECT NULLIF(value, '(none)') ...
 
 
 LEAST(value , ...)
+
+
+GREATEST(VARIADIC anyarray)
+
+
+LEAST(VARIADIC anyarray)
 
 

@@ -12697,6 +12703,11 @@ SELECT NULLIF(value, '(none)') ...
 make them return NULL if any argument is NULL, rather than only when
 all are NULL.

+
+   
+These functions supports passing parameters as a array after
+VARIADIC keyword.
+   
   
  
 
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index db3777d15e..01d7f0e02c 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1854,13 +1854,18 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_MinMaxExpr:
 			{
 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
-int			nelems = list_length(minmaxexpr->args);
+int			nelems;
 TypeCacheEntry *typentry;
 FmgrInfo   *finfo;
 FunctionCallInfo fcinfo;
 ListCell   *lc;
 int			off;
 
+if (minmaxexpr->args)
+	nelems = list_length(minmaxexpr->args);
+else
+	nelems = 1;
+
 /* Look up the btree comparison function for the datatype */
 typentry = lookup_type_cache(minmaxexpr->minmaxtype,
 			 TYPECACHE_CMP_PROC);
@@ -1897,16 +1902,29 @@ ExecInitExprRec(Expr *node, ExprState *state,
 scratch.d.minmax.finfo = finfo;
 scratch.d.minmax.fcinfo_data = fcinfo;
 
-/* evaluate expressions into minmax->values/nulls */
-off = 0;
-foreach(lc, minmaxexpr->args)
+if (minmaxexpr->args)
 {
-	Expr	   *e = (Expr *) lfirst(lc);
+	scratch.d.minmax.variadic_arg = false;
 
-	ExecInitExprRec(e, state,
-	[off],
-	[off]);
-	off++;
+	/* evaluate expressions into minmax->values/nulls */
+	off = 0;
+	foreach(lc, minmaxexpr->args)
+	{
+		Expr	   *e = (Expr *) lfirst(lc);
+
+		ExecInitExprRec(e, state,
+		[off],
+		[off]);
+		off++;
+	}
+}
+else
+{
+	scratch.d.minmax.variadic_arg = true;
+
+	ExecInitExprRec(minmaxexpr->variadic_arg, state,
+		[0],
+		[0]);
 }
 
 /* and push the final comparison */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..748c950885 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2819,6 +2819,55 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
+	if (op->d.minmax.variadic_arg)
+	{
+		ArrayIterator array_iterator;
+		ArrayType  *arr;
+		Datum	value;
+		bool	isnull;
+
+		if (nulls[0])
+			return;
+
+		arr = DatumGetArrayTypeP(values[0]);
+
+		array_iterator = array_create_iterator(arr, 0, NULL);
+		while (array_iterate(array_iterator, , ))
+		{
+			if (isnull)
+continue;
+
+			if (*op->resnull)
+			{
+/* first nonnull input */
+*op->resvalue = value;
+*op->resnull = false;
+			}
+			else
+			{
+int			cmpresult;
+
+Assert(fcinfo->nargs == 2);
+
+/* apply comparison function */
+fcinfo->args[0].value = *op->resvalue;
+fcinfo->args[1].value = value;
+
+fcinfo->isnull = false;
+cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
+if (fcinfo->isnull) /* probably should not happen */
+	continue;
+
+if (cmpresult > 0 && operator == IS_LEAST)
+	*op->resvalue = value;
+else if (cmpresult < 0 && operator == IS_GREATEST)
+	*op->resvalue = value;
+			}
+		}
+
+		return;
+	}
+
 	for (off = 0; off < op->d.minmax.nelems; off++)
 	{
 		/* ignore NULL inputs */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e15724bb0e..e8ad89799f 100644
--- 

Re: proposal: variadic argument support for least, greatest function

2019-02-20 Thread Chapman Flack
The following review has been posted through the commitfest application:
make installcheck-world:  tested, passed
Implements feature:   tested, passed
Spec compliant:   not tested
Documentation:not tested

Latest patch passes installcheck-world as of d26a810 and does what it sets out 
to do.

I am not sure I have an answer to the objections being raised on grounds of 
taste. To me, it's persuasive that GREATEST and LEAST are described in the 
docco as functions, they are used much like variadic functions, and this patch 
allows them to be used in the ways you would expect variadic functions to be 
usable.

But as to technical readiness, this builds and passes installcheck-world. The 
functions behave as expected (and return null if passed an empty array, or an 
array containing only nulls, or variadic null::foo[]).

Still no corresponding regression tests or doc.

The new status of this patch is: Waiting on Author


Re: proposal: variadic argument support for least, greatest function

2019-02-12 Thread Pavel Stehule
Hi

út 12. 2. 2019 v 2:00 odesílatel Chapman Flack 
napsal:

> The following review has been posted through the commitfest application:
> make installcheck-world:  tested, failed
> Implements feature:   not tested
> Spec compliant:   not tested
> Documentation:not tested
>
> The argument for consistency with other functions that are variadic makes
> sense to me: although they are different from ordinary variadic functions
> in the type unification they do, their description in the manual simply
> calls them functions without calling attention to any way that they are
> different beasts. So, a reader might reasonably be surprised that VARIADIC
> doesn't work in the usual way.
>
> This patch applies (with some offsets) but the build produces several
> incompatible pointer type assignment warnings, and fails on errors where
> fcinfo->arg is no longer a thing (so should be rebased over the
> variable-length function call args patch).
>
> It does not yet add regression tests, or update the documentation in
> func.sgml.


here is fixed patch

Regards

Pavel
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index db3777d15e..01d7f0e02c 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1854,13 +1854,18 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_MinMaxExpr:
 			{
 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
-int			nelems = list_length(minmaxexpr->args);
+int			nelems;
 TypeCacheEntry *typentry;
 FmgrInfo   *finfo;
 FunctionCallInfo fcinfo;
 ListCell   *lc;
 int			off;
 
+if (minmaxexpr->args)
+	nelems = list_length(minmaxexpr->args);
+else
+	nelems = 1;
+
 /* Look up the btree comparison function for the datatype */
 typentry = lookup_type_cache(minmaxexpr->minmaxtype,
 			 TYPECACHE_CMP_PROC);
@@ -1897,16 +1902,29 @@ ExecInitExprRec(Expr *node, ExprState *state,
 scratch.d.minmax.finfo = finfo;
 scratch.d.minmax.fcinfo_data = fcinfo;
 
-/* evaluate expressions into minmax->values/nulls */
-off = 0;
-foreach(lc, minmaxexpr->args)
+if (minmaxexpr->args)
 {
-	Expr	   *e = (Expr *) lfirst(lc);
+	scratch.d.minmax.variadic_arg = false;
 
-	ExecInitExprRec(e, state,
-	[off],
-	[off]);
-	off++;
+	/* evaluate expressions into minmax->values/nulls */
+	off = 0;
+	foreach(lc, minmaxexpr->args)
+	{
+		Expr	   *e = (Expr *) lfirst(lc);
+
+		ExecInitExprRec(e, state,
+		[off],
+		[off]);
+		off++;
+	}
+}
+else
+{
+	scratch.d.minmax.variadic_arg = true;
+
+	ExecInitExprRec(minmaxexpr->variadic_arg, state,
+		[0],
+		[0]);
 }
 
 /* and push the final comparison */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index a018925d4e..748c950885 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2819,6 +2819,55 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
+	if (op->d.minmax.variadic_arg)
+	{
+		ArrayIterator array_iterator;
+		ArrayType  *arr;
+		Datum	value;
+		bool	isnull;
+
+		if (nulls[0])
+			return;
+
+		arr = DatumGetArrayTypeP(values[0]);
+
+		array_iterator = array_create_iterator(arr, 0, NULL);
+		while (array_iterate(array_iterator, , ))
+		{
+			if (isnull)
+continue;
+
+			if (*op->resnull)
+			{
+/* first nonnull input */
+*op->resvalue = value;
+*op->resnull = false;
+			}
+			else
+			{
+int			cmpresult;
+
+Assert(fcinfo->nargs == 2);
+
+/* apply comparison function */
+fcinfo->args[0].value = *op->resvalue;
+fcinfo->args[1].value = value;
+
+fcinfo->isnull = false;
+cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
+if (fcinfo->isnull) /* probably should not happen */
+	continue;
+
+if (cmpresult > 0 && operator == IS_LEAST)
+	*op->resvalue = value;
+else if (cmpresult < 0 && operator == IS_GREATEST)
+	*op->resvalue = value;
+			}
+		}
+
+		return;
+	}
+
 	for (off = 0; off < op->d.minmax.nelems; off++)
 	{
 		/* ignore NULL inputs */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b44ead269f..4d1c209c6a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1942,6 +1942,7 @@ _copyMinMaxExpr(const MinMaxExpr *from)
 	COPY_SCALAR_FIELD(inputcollid);
 	COPY_SCALAR_FIELD(op);
 	COPY_NODE_FIELD(args);
+	COPY_NODE_FIELD(variadic_arg);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 1e169e0b9c..aebc0115ea 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -635,6 +635,7 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
 	COMPARE_SCALAR_FIELD(inputcollid);
 	COMPARE_SCALAR_FIELD(op);
 	

Re: proposal: variadic argument support for least, greatest function

2019-01-08 Thread Pavel Stehule
st 9. 1. 2019 v 1:07 odesílatel Tom Lane  napsal:

> Pavel Stehule  writes:
> > We cannot to write
> > SELECT least(VARIADIC ARRAY[1,2,3]);
> > Attached patch add this possibility to least, greatest functions.
>
> TBH, I don't find that natural at all.  If I were looking for the
> functionality "smallest element of an array", I think I'd expect to find
> that exposed as "array_smallest(anyarray) returns anyelement", not as
> some weird syntax option for LEAST.
>

The target of this patch is a consistency LEAST, GREATEST variadic
functions (implementet) with generic variadic functions.

Sure it is possible to implement array_smallest(anyarray), but it
different. This patch try to eliminate unpleasing surprising about
different behave LEAST, GREATEST from other variadic functions.


> It also seems rather inconsistent that this behaves so differently
> from, eg,
>
> =# select least(array[1,2], array[3,4]);
>  least
> ---
>  {1,2}
> (1 row)
>
> Normally, if you have a variadic function, it doesn't also take arrays,
> so that there's less possibility for confusion.
>

This is different case - the keyword VARIADIC was not used here.


> The implementation seems mighty ugly too, in that it has to treat this
> as entirely disjoint from MinMaxExpr's normal argument interpretation.
> But that seems like a symptom of the fact that the definition is
> disjointed itself.
>

I don't think so there is any other possibility - I have not a possibility
to unpack a array to elements inside analyze stage.


> In short, I'd rather see this done with a couple of array functions,
> independently of MinMaxExpr.
>

It doesn't help to user, when they try to use VARIADIC keyword on LEAST,
GREATEST functions.

Regards

Pavel


>
> regards, tom lane
>


Re: proposal: variadic argument support for least, greatest function

2019-01-08 Thread Tom Lane
Pavel Stehule  writes:
> We cannot to write
> SELECT least(VARIADIC ARRAY[1,2,3]);
> Attached patch add this possibility to least, greatest functions.

TBH, I don't find that natural at all.  If I were looking for the
functionality "smallest element of an array", I think I'd expect to find
that exposed as "array_smallest(anyarray) returns anyelement", not as
some weird syntax option for LEAST.

It also seems rather inconsistent that this behaves so differently
from, eg,

=# select least(array[1,2], array[3,4]);
 least 
---
 {1,2}
(1 row)

Normally, if you have a variadic function, it doesn't also take arrays,
so that there's less possibility for confusion.

The implementation seems mighty ugly too, in that it has to treat this
as entirely disjoint from MinMaxExpr's normal argument interpretation.
But that seems like a symptom of the fact that the definition is
disjointed itself.

In short, I'd rather see this done with a couple of array functions,
independently of MinMaxExpr.

regards, tom lane



Re: proposal: variadic argument support for least, greatest function

2018-11-10 Thread Pavel Stehule
so 10. 11. 2018 v 19:12 odesílatel Vik Fearing 
napsal:

> On 08/11/2018 15:59, Pavel Stehule wrote:
> > Hi
> >
> > We can pass variadic arguments as a array to any variadic function. But
> > some our old variadic functions doesn't supports this feature.
> >
> > We cannot to write
> >
> > SELECT least(VARIADIC ARRAY[1,2,3]);
> >
> > Attached patch add this possibility to least, greatest functions.
>
> Is there any particular reason you didn't just make least and greatest
> actual functions?
>

These functions has are able to use most common type and enforce casting.
Generic variadic function cannot do it.

Regards

Pavel


-- 
> Vik Fearing  +33 6 46 75 15 36
> http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support
>


Re: proposal: variadic argument support for least, greatest function

2018-11-10 Thread Andrew Gierth
> "Vik" == Vik Fearing  writes:

 >> Attached patch add this possibility to least, greatest functions.

 Vik> Is there any particular reason you didn't just make least and
 Vik> greatest actual functions?

least() and greatest() have some type unification logic that I don't
think works for actual functions.

create function s(variadic anyarray) returns anyelement
  language sql immutable
  as $$ select min(v) from unnest($1) u(v); $$;

select s(1,2,3); -- works
select s(1,2,3.0);  -- ERROR:  function s(integer, integer, numeric) does not 
exist
select least(1,2,3.0);  -- works

-- 
Andrew (irc:RhodiumToad)



Re: proposal: variadic argument support for least, greatest function

2018-11-10 Thread Vik Fearing
On 08/11/2018 15:59, Pavel Stehule wrote:
> Hi
> 
> We can pass variadic arguments as a array to any variadic function. But
> some our old variadic functions doesn't supports this feature.
> 
> We cannot to write
> 
> SELECT least(VARIADIC ARRAY[1,2,3]);
> 
> Attached patch add this possibility to least, greatest functions.

Is there any particular reason you didn't just make least and greatest
actual functions?
-- 
Vik Fearing  +33 6 46 75 15 36
http://2ndQuadrant.fr PostgreSQL : Expertise, Formation et Support



proposal: variadic argument support for least, greatest function

2018-11-08 Thread Pavel Stehule
Hi

We can pass variadic arguments as a array to any variadic function. But
some our old variadic functions doesn't supports this feature.

We cannot to write

SELECT least(VARIADIC ARRAY[1,2,3]);

Attached patch add this possibility to least, greatest functions.

Regards

Pavel
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 885da18306..53021b1ae2 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1852,13 +1852,18 @@ ExecInitExprRec(Expr *node, ExprState *state,
 		case T_MinMaxExpr:
 			{
 MinMaxExpr *minmaxexpr = (MinMaxExpr *) node;
-int			nelems = list_length(minmaxexpr->args);
+int			nelems;
 TypeCacheEntry *typentry;
 FmgrInfo   *finfo;
 FunctionCallInfo fcinfo;
 ListCell   *lc;
 int			off;
 
+if (minmaxexpr->args)
+	nelems = list_length(minmaxexpr->args);
+else
+	nelems = 1;
+
 /* Look up the btree comparison function for the datatype */
 typentry = lookup_type_cache(minmaxexpr->minmaxtype,
 			 TYPECACHE_CMP_PROC);
@@ -1895,16 +1900,29 @@ ExecInitExprRec(Expr *node, ExprState *state,
 scratch.d.minmax.finfo = finfo;
 scratch.d.minmax.fcinfo_data = fcinfo;
 
-/* evaluate expressions into minmax->values/nulls */
-off = 0;
-foreach(lc, minmaxexpr->args)
+if (minmaxexpr->args)
 {
-	Expr	   *e = (Expr *) lfirst(lc);
+	scratch.d.minmax.variadic_arg = false;
 
-	ExecInitExprRec(e, state,
-	[off],
-	[off]);
-	off++;
+	/* evaluate expressions into minmax->values/nulls */
+	off = 0;
+	foreach(lc, minmaxexpr->args)
+	{
+		Expr	   *e = (Expr *) lfirst(lc);
+
+		ExecInitExprRec(e, state,
+		[off],
+		[off]);
+		off++;
+	}
+}
+else
+{
+	scratch.d.minmax.variadic_arg = true;
+
+	ExecInitExprRec(minmaxexpr->variadic_arg, state,
+		[0],
+		[0]);
 }
 
 /* and push the final comparison */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index c08df6f162..e26487d315 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2791,6 +2791,53 @@ ExecEvalMinMax(ExprState *state, ExprEvalStep *op)
 	/* default to null result */
 	*op->resnull = true;
 
+	if (op->d.minmax.variadic_arg)
+	{
+		ArrayIterator array_iterator;
+		ArrayType  *arr;
+		Datum	value;
+		bool	isnull;
+
+		if (nulls[0])
+			return;
+
+		arr = DatumGetArrayTypeP(values[0]);
+
+		array_iterator = array_create_iterator(arr, 0, NULL);
+		while (array_iterate(array_iterator, , ))
+		{
+			if (isnull)
+continue;
+
+			if (*op->resnull)
+			{
+/* first nonnull input */
+*op->resvalue = value;
+*op->resnull = false;
+			}
+			else
+			{
+int			cmpresult;
+
+/* apply comparison function */
+fcinfo->arg[0] = *op->resvalue;
+fcinfo->arg[1] = value;
+
+fcinfo->isnull = false;
+cmpresult = DatumGetInt32(FunctionCallInvoke(fcinfo));
+if (fcinfo->isnull) /* probably should not happen */
+	continue;
+
+if (cmpresult > 0 && operator == IS_LEAST)
+	*op->resvalue = value;
+else if (cmpresult < 0 && operator == IS_GREATEST)
+	*op->resvalue = value;
+			}
+		}
+
+		return;
+	}
+
 	for (off = 0; off < op->d.minmax.nelems; off++)
 	{
 		/* ignore NULL inputs */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e8ea59e34a..3df2d42ad6 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -1942,6 +1942,7 @@ _copyMinMaxExpr(const MinMaxExpr *from)
 	COPY_SCALAR_FIELD(inputcollid);
 	COPY_SCALAR_FIELD(op);
 	COPY_NODE_FIELD(args);
+	COPY_NODE_FIELD(variadic_arg);
 	COPY_LOCATION_FIELD(location);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3bb91c9595..1c6fddac2a 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -634,6 +634,7 @@ _equalMinMaxExpr(const MinMaxExpr *a, const MinMaxExpr *b)
 	COMPARE_SCALAR_FIELD(inputcollid);
 	COMPARE_SCALAR_FIELD(op);
 	COMPARE_NODE_FIELD(args);
+	COMPARE_NODE_FIELD(variadic_arg);
 	COMPARE_LOCATION_FIELD(location);
 
 	return true;
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index a10014f755..2fbdcd78f8 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -465,6 +465,9 @@ exprTypmod(const Node *expr)
 int32		typmod;
 ListCell   *arg;
 
+if (mexpr->variadic_arg)
+	return exprTypmod((Node *) mexpr->variadic_arg);
+
 if (exprType((Node *) linitial(mexpr->args)) != minmaxtype)
 	return -1;
 typmod = exprTypmod((Node *) linitial(mexpr->args));
@@ -2065,7 +2068,15 @@ expression_tree_walker(Node *node,
 		case T_CoalesceExpr:
 			return walker(((CoalesceExpr *) node)->args, context);
 		case T_MinMaxExpr:
-			return walker(((MinMaxExpr *) node)->args, context);
+			{
+MinMaxExpr *mexpr =