使用函数调用中的UUID字段分配复杂类型

时间:2014-07-01 17:27:30

标签: postgresql stored-procedures rows plpgsql uuid

我正在使用PostgreSQL 9.3,使用plpgsql函数:

CREATE TEMP TABLE uuid_inside (
    id  uuid PRIMARY KEY
);

CREATE FUNCTION uuid_test_func(id uuid)
  RETURNS uuid_inside AS
$$
DECLARE
    res_uuid_inside uuid_inside;
BEGIN
    IF (id = '00000000-0000-0000-0000-000000000001'::uuid) THEN
        SELECT uuid_test_func('00000000-0000-0000-0000-000000000000'::uuid)
            INTO res_uuid_inside;
        RETURN res_uuid_inside;
    END IF;

    res_uuid_inside.id := id;

    RETURN res_uuid_inside;
END;
$$
LANGUAGE plpgsql;

呼叫:

SELECT uuid_test_func('00000000-0000-0000-0000-000000000001'::uuid);

消息:

  

错误:uuid的输入语法无效:"(00000000-0000-0000-0000-000000000000)"
  SQL状态:22P02

但这很好用:

SELECT uuid_test_func('00000000-0000-0000-0000-000000000002'::uuid);

问题不在于递归函数调用 - 原始代码是指内部的其他函数。

1 个答案:

答案 0 :(得分:1)

简单功能

你的函数中的递归似乎毫无意义。这个简单的sql函数完成了这项工作(没有嵌套,没有复合类型包装器):

CREATE FUNCTION uuid_test_func(id uuid)
  RETURNS uuid AS
$func$
SELECT CASE WHEN $1 = '00000000-0000-0000-0000-000000000001'::uuid
                 THEN '00000000-0000-0000-0000-000000000000'::uuid
            ELSE $1
       END
$func$ LANGUAGE plpgsql;

但这可能只是因为演示的简化。

解决原始

中的问题

至于错误消息。您正在遇到PL / pgSQL令人困惑的“功能”:
复合类型分配需要每个类型列一列。将复合类型作为一个整体分配不是一种选择。

这与UUID类型本身无关。

此修改版本可以使用:

CREATE OR REPLACE FUNCTION uuid_test_func(id uuid)
  RETURNS uuid_inside AS
$func$
DECLARE
    res_uuid_inside uuid_inside;
BEGIN
   IF (id = '00000000-0000-0000-0000-000000000001'::uuid) THEN
       SELECT * FROM uuid_test_func('00000000-0000-0000-0000-000000000000'::uuid)
       INTO   res_uuid_inside.id;
  --   INTO   res_uuid_inside;    -- would work, too - 1st col is assigned
       RETURN res_uuid_inside;
   END IF;

   res_uuid_inside.id := id;

   RETURN res_uuid_inside;
END
$func$ LANGUAGE plpgsql;

密切相关的问题:
Passing array of a composite type to stored procedure

更简单的功能

那就是说,我建议使用这种简化形式(保持递归和复合结果):

CREATE OR REPLACE FUNCTION uuid_test_func(id uuid)
  RETURNS uuid_inside AS
$func$
BEGIN
   IF (id = '00000000-0000-0000-0000-000000000001'::uuid) THEN
      RETURN (SELECT f FROM uuid_test_func('00000000-0000-0000-0000-000000000000'::uuid) f);
   ELSE
      RETURN row(id)::uuid_inside;
   END IF;
END
$func$ LANGUAGE plpgsql;