PostgreSQL: сохранить функцию в столбце как значение - PullRequest
2 голосов
/ 09 ноября 2011

Могут ли функции храниться как анонимные функции непосредственно в столбце как его значение?

Допустим, я хочу, чтобы эта функция была сохранена в столбце. Пример (псевдокод):

Таблица my_table: pk (int), my_function (func)

func (x) {return x * 100}

А позже используйте его как:

select 
    t.my_function(some_input) AS output
from 
    my_table as t 
where t.pk = 1999

Функция может отличаться для каждого ПК.

1 Ответ

6 голосов
/ 09 ноября 2011

Ваш заголовок запрашивает нечто иное, чем ваш пример.

  1. Функция должна быть создана , прежде чем вы сможете ее вызвать.(название)
  2. Необходимо выражение .Вам понадобится мета-функция для этого.(пример)

Я представлю решения для обоих.

1.Динамическая оценка выражений

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

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;

CREATE OR REPLACE FUNCTION x.f1(int)
  RETURNS int AS
$$SELECT $1 * 100;$$
  LANGUAGE sql IMMUTABLE;

CREATE OR REPLACE FUNCTION x.f2(text)
  RETURNS text AS
$$SELECT $1 || '_foo';$$
  LANGUAGE sql IMMUTABLE;

CREATE TABLE x.my_expr (expr text PRIMARY KEY, def text, rettype text);

INSERT INTO x.my_expr VALUES
 ('x', $$x.f1(3)$$, 'int')
,('y', $$x.f2('bar')$$, 'text')
;

CREATE OR REPLACE FUNCTION x.f_eval(text, _type anyelement, OUT _result anyelement)
  AS
$x$
BEGIN

EXECUTE
'SELECT ' || (SELECT def FROM x.my_expr WHERE expr = $1)
INTO _result;

END;
$x$
LANGUAGE plpgsql;

Звоните:

SELECT x.f_eval('x', (SELECT rettype FROM x.my_expr WHERE expr = 'x'));
 f_eval
--------
 300
(1 row)

SELECT x.f_eval('y', (SELECT rettype FROM x.my_expr WHERE expr = 'y'));
 f_eval
---------
 bar_foo
(1 Zeile)

2.Динамическое создание и использование функций

Можно динамически создавать функции, а затем использовать их.Вы не можете сделать это с простым SQL, однако.Для этого вам понадобится другая функция или хотя бы блок анонимного кода (оператор DO) , представленный в PostgreSQL 9.0.

Может работать так:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.my_func (func text PRIMARY KEY, def text);

INSERT INTO x.my_func VALUES('f'
, $$CREATE OR REPLACE FUNCTION f(int)
  RETURNS int AS
'SELECT $1 * 100;'
  LANGUAGE sql IMMUTABLE$$);

CREATE OR REPLACE FUNCTION x.f_create_func(text)
RETURNS void AS $x$
BEGIN

EXECUTE (SELECT def FROM x.my_func WHERE func = $1);

END;
$x$
LANGUAGE plpgsql;

Вызов:

select x.f_create_func('f');
SELECT f(3);

Вы можете отказаться от этой функции впоследствии.

В большинстве случаев вам следует просто создать вместо этого функции и покончить с ними.Используйте отдельные схемы, если у вас есть проблемы с несколькими версиями или привилегиями.

Для получения дополнительной информации о функциях, которые я использовал здесь, см. мой соответствующий ответ на dba.stackexchange.com .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...