November 17th, 2009 by depesz | Tags: , , , , , , | 1 comment »
Did it help? If yes - maybe you can help me? Donate BTC to 19zPa5diT2LZqGtTi8f8bfApLn8rw9zBHx

Pavel Stehule – hero for everybody writing stored procedures, wrote, and later Tom Lane committed patch which adds named arguments for functions:

Log Message:
-----------
Support use of function argument names to identify which actual arguments
match which function parameters. The syntax uses AS, for example
funcname(value AS arg1, anothervalue AS arg2)
 
Pavel Stehule

So, let's see how it works.

CREATE OR REPLACE FUNCTION test(
IN x TEXT,
IN y TEXT,
OUT z TEXT
) as $$
BEGIN
z:= regexp_replace( x, y, '', 'g' );
RETURN;
END;
$$ language plpgsql;

This is pretty simple function that replaces removes parts of string that match given regexp:

# select test('Hubert Depesz Lubaczewski', '[a-z]+( |$)');
test
──────
HDL
(1 row)

Now, I can call this function as:

# select test('Hubert Depesz Lubaczewski' as x, '[a-z]+( |$)' as y);

Which doesn't make it very special, but the fact that the arguments are named means I can reorder them:

# select test('[a-z]+( |$)' as y, 'PostgreSQL Is Absolutely Great' as x);
test
────────────────
PostgreSQL IAG
(1 row)

Which is cool, but not something that I would call life-changing. The real power in here comes when we'll combine this patch with previous patch (also by Pavel), which added default values for functions.

As you perhaps remember, it had the limitation that you couldn't use default value for 1st argument, but provide argument for 2nd.

But now – it's no longer a problem:

CREATE OR REPLACE FUNCTION test(
IN x TEXT DEFAULT 'DefaultX',
IN y TEXT DEFAULT 'DefaultY',
IN z TEXT DEFAULT 'DefaultZ',
OUT o TEXT
) as $$
BEGIN
o := printf( 'x=[%] , y=[%] , z=[%]', x, y, z );
RETURN;
END;
$$ language plpgsql;

( printf function provided by Alvaro Herrera )

And now I can:

# select test();
test
────────────────────────────────────────────
x=[DefaultX] , y=[DefaultY] , z=[DefaultZ]
(1 row)
 
# select test('a');
test
─────────────────────────────────────
x=[a] , y=[DefaultY] , z=[DefaultZ]
(1 row)
 
# select test('a', 'b');
test
──────────────────────────────
x=[a] , y=[b] , z=[DefaultZ]
(1 row)
 
# select test('a', 'b', 'c');
test
───────────────────────
x=[a] , y=[b] , z=[c]
(1 row)
 
# select test('c' as z);
test
─────────────────────────────────────
x=[DefaultX] , y=[DefaultY] , z=[c]
(1 row)

Of course it should work in all languages that support argument names. For example pl/Python:

CREATE OR REPLACE FUNCTION pytest(
x TEXT,
y TEXT,
z TEXT
) RETURNS TEXT as $$
return "Python: x = [%s], y = [%s], z = [%s]" % (x, y, z)
$$ language plpythonu;

And call:

# select pytest('depesz' as y, 'hubert' as x, 'lubaczewski' as z);
pytest
───────────────────────────────────────────────────────
Python: x = [hubert], y = [depesz], z = [lubaczewski]
(1 row)

This is very cool. Great work Pavel.

  1. One comment

  2. # moltonel
    Nov 17, 2009

    Hey Pavel, stop that ! You’ve just removed another reason to keep code outside of postgres ! How can I keep pretending that RDBMs are just “dumb data stores” now ?

    /me is dancing around joyfully :)

Leave a comment