PostgreSQL timestamp / числовая точность игнорируется на параметре функции?


Даны следующие функции PostgreSQL:

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;

Ожидаете ли вы, что выходные данные этих функций будут показывать результат в соответствии с типом, объявленным в параметре функции?

Я был очень удивлен, обнаружив, что точность была сохранена и показана в "уведомлении", несмотря на тип параметра, ограничивающий точность.

Это ошибка или я просто думаю об этом неправильно?

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

Я использую PostgreSQL 9.3.

Редактировать: Если я сделаю это, я ... получите то, что я ожидаю:

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;

Дает:

db=> SELECT fn_dtm(now());
NOTICE:  fn: 2015-02-05 10:38:38+00
1 3

1 ответ:

Возможно, это не то, что вы ожидаете, но именно так это работает.

Причина ясна, если вы спросите Postgres для определения функции; запустите \sf fn_num в psql или SELECT pg_get_functiondef('fn_num'::regproc), и он даст вам:

CREATE OR REPLACE FUNCTION public.fn_num(num numeric) ...
Таким образом, к тому времени, когда Postgres создает вашу функцию, информация о точности/масштабе уже отброшена. Типы возвращаемых данных страдают от той же проблемы.

Это можно обойти, используя домены для псевдонимов типов, участвующих:

CREATE DOMAIN timestamptz_seconds AS timestamptz(0);
CREATE FUNCTION fn_dtm(dtm timestamptz_seconds) ...

Это может быть особенно полезно для типов возвращаемых данных, если требуется сохранить точность определения результирующего набора. Но в большинстве случаев, как вы уже отмечали, вы можете получить тот же результат с некоторыми явными приведениями в вашем функциональном теле.