July 31st, 2008 by depesz | Tags: , , , | 1 comment »
Did it help? If yes - maybe you can help me? Donate BTC to 19zPa5diT2LZqGtTi8f8bfApLn8rw9zBHx

Pavel Stehule wrote, and then Tom Lane committed (on 16th of July), patch which adds to PostgreSQL support for functions with variable number of arguments.

These function are called “VARIADIC", and up until now writing such a function was impossible.

You could overcome this limitation by:

  • defining a lot of functions with the same name, but different sets
    of arguments
  • passing array to function

New patch makes creation of such functions a breeze:

Support "variadic" functions, which can accept a variable number of arguments
so long as all the trailing arguments are of the same (non-array) type.
The function receives them as a single array argument (which is why they
have to all be the same type).
 
It might be useful to extend this facility to aggregates, but this patch
doesn't do that.
 
This patch imposes a noticeable slowdown on function lookup --- a follow-on
patch will fix that by adding a redundant column to pg_proc.
 
Pavel Stehule

As for last note from commit log – of course there was second patch which made the lookup faster.

How do these functions work? It's pretty simple:

CREATE FUNCTION get_powers(IN base INT4, VARIADIC powers INT4[], OUT power INT8) RETURNS SETOF INT8 AS $$
DECLARE
i int4;
BEGIN
FOR i IN SELECT generate_subscripts(powers, 1) LOOP
power := base ^ powers[i];
RETURN NEXT;
END LOOP;
RETURN;
END;
$$ language plpgsql;

This function takes following arguments:

  1. obligatory integer, which will be base for power
  2. 1+ integers which will be use as power factor

It will return recordset, with only 1 column (named power), which will contain base raised to given power:

# select * from get_powers(2, 3);
power
-------
8
(1 row)
# select * from get_powers(2, 3, 5, 10);
power
-------
8
32
1024
(3 rows)

If I will not give any powers, exception will be raised:

# select * from get_powers(2);
ERROR: function get_powers(integer) does not exist
LINE 1: select * from get_powers(2);
^

Now, if only I could pass variadic to pl/perl in sane way, I could have sql version of sprintf() :)

  1. One comment

  2. # Kostas
    Nov 29, 2008

    Indeed, as you mentioned, it is possible to do this by passing an array. And probably in a case such as described in the example, people should still be using an array. IMO, the syntax like
    select * from get_powers(2, 3, 5, 10);
    is less clear about whats being done than
    select * from get_powers(2, array[3, 5, 10]);

    The more compelling reason to have variadic functions is to allow a default value for an omitted parameter!
    I.e. as our code evolves, we often add some new parameters to the function, but would like to not rewrite other code that refers to the said function – when we call the old way, with the parameter omitted, we want some default value.
    What we see here so far is not going to solve the problem for us, even if all the new parameters are of the same type, say strings. Indeed, because there’s an exception raised when the argument was omitted makes it impossible.

Leave a comment