Given the following PostgreSQL functions:
CREATE OR REPLACE FUNCTION fn_dtm (
dtm timestamptz(0))
RETURNS void AS $$
BEGIN
RAISE NOTICE 'fn: %, %', dtm, dtm::timestamptz(0);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION fn_num (
num numeric(5, 2))
RETURNS void AS $$
BEGIN
RAISE NOTICE 'num: %, %', num, num::numeric(5, 2);
END;
$$ LANGUAGE plpgsql;
Would you expect the output of these functions to show the result as per the type declared in the function parameter?
I was very surprised to find that the precision was retained and shown in the "NOTICE" despite the parameter type limiting the precision.
Is this a bug or am I just thinking about it the wrong way?
Here is the output:
db=> SELECT fn_dtm(now());
NOTICE: fn: 2015-02-05 10:25:44.184+00, 2015-02-05 10:25:44+00
db=> SELECT fn_num(1.23456789);
NOTICE: num: 1.23456789, 1.23
I am using PostgreSQL 9.3.
EDIT: If I do this I get what I expect:
CREATE OR REPLACE FUNCTION fn_dtm (
dtm timestamptz(0))
RETURNS void AS $$
BEGIN
dtm = dtm::timestamptz(0); ----- CHANGE PRECISION
RAISE NOTICE 'fn: %', dtm;
END;
$$ LANGUAGE plpgsql;
Gives:
db=> SELECT fn_dtm(now());
NOTICE: fn: 2015-02-05 10:38:38+00
It's probably not what you'd expect, but that's the way it works.
The cause is clear if you ask Postgres for the function's definition; run \sf fn_num in psql, or SELECT pg_get_functiondef('fn_num'::regproc), and it will give you:
CREATE OR REPLACE FUNCTION public.fn_num(num numeric) ...
So by the time Postgres creates your function, the precision/scale information has already been discarded. Return types suffer from the same issue.
It is possible to work around this by using domains to alias the types involved:
CREATE DOMAIN timestamptz_seconds AS timestamptz(0);
CREATE FUNCTION fn_dtm(dtm timestamptz_seconds) ...
This can be particularly useful for return types if you need to retain the precision in the definition of your result set. But in most cases, as you pointed out, you can get the same outcome with some explicit casts in your function body.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With