PL / pgSQL函数不会按预期返回自定义(记录)类型

时间:2015-06-25 20:50:16

标签: postgresql function recursion plpgsql

我的职责是提取XML节点。代码如下:

var CarouselView = Ember.View.extend({
  templateName: 'views/carousel',
  elementId: 'carousel',
  contentBinding: 'content',
  ...

正如您所看到的,该函数是递归的,目标是从我们没有信息的多个XML节点收集字段值,我们在标记下有多少个节点。 (我有一个带返回表的版本,但该方法太慢。)我使用自己定义的自定义类型,当我使用CREATE TYPE xml_node_looper_record AS ( allomany xml, i integer, actual_node text, nodi_parts text[] ); CREATE OR REPLACE FUNCTION ds.xml_node_looper_rec(rec xml_node_looper_record) RETURNS SETOF xml_node_looper_record AS $BODY$ DECLARE nodes text[]; field_val text; r xml_node_looper_record; n integer; BEGIN nodes = xpath(rec.actual_node, rec.allomany); IF nodes[1] IS NOT NULL THEN rec.i = rec.i + 1; FOR n IN 1..array_upper(nodes, 1) LOOP IF rec.i = array_upper(rec.nodi_parts, 1) THEN field_val = trim(ARRAY[xpath(rec.actual_node || '/text()', rec.allomany)]::text, ' {}"'); IF field_val IS NOT NULL AND field_val != '' THEN RAISE NOTICE '% % % %', n, rec.actual_node, rec.i, field_val; RETURN NEXT (NULL::xml, rec.i, rec.actual_node, ARRAY[field_val]::text[]); END IF; END IF; SELECT ds.xml_node_looper_rec((rec.allomany, rec.i, rec.actual_node || '[' || n::text || ']' || rec.nodi_parts[rec.i + 1], rec.nodi_parts)) INTO r; END LOOP; END IF; END; $BODY$ LANGUAGE plpgsql VOLATILE COST 100; 检查返回值时,我可以在“消息”选项卡上看到pgAdmin中的结果,但RAISE NOTICE命令不返回任何内容,只返回一个空表。

我的类型的参数:

  • allomany:XML数据
  • i:nodi_parts的实际深度
  • actual_node:XML节点,我想提取。可以有多个 节点,我用[]标记它们。例如: / tagone / tagtwo [] / tagthree [] /字段名
  • nodi_parts:来自actual_node,用[]分割。对于 示例ARRAY [" / tagone / tagtwo"," / tagthree"," / fieldname"]

有什么问题?

1 个答案:

答案 0 :(得分:2)

您不会传播嵌套调用的结果。 RETURN NEXT将结果推送到与函数调用相关的堆栈。但是这个堆栈是私有的 - 如果调用者没有获取此堆栈,则清除结果。无论如何 - 任何函数实例(被调用函数)都有自己的结果堆栈。此堆栈未共享。

PL / pgSQL中的递归表函数应如下所示:

postgres=# CREATE OR REPLACE FUNCTION foo(level int) RETURNS SETOF int AS $$
BEGIN
  IF level > 5 THEN RETURN; END IF;
  RETURN NEXT level;
  --!! must to take result of nested call
  RETURN QUERY SELECT * FROM foo(level + 1); 
  RETURN;
END;
$$ LANGUAGE plpgsql;

postgres=# SELECT * FROM foo(1);
┌─────┐
│ foo │
╞═════╡
│   1 │
│   2 │
│   3 │
│   4 │
│   5 │
└─────┘
(5 rows)

您的代码相当于代码:

postgres=# CREATE OR REPLACE FUNCTION foo(level int) RETURNS SETOF int AS $$
BEGIN
  IF level > 5 THEN RETURN; END IF;
  RETURN NEXT level;
  -- error, only call of nested function, but returned table is lost
  PERFORM foo(level + 1);
  RETURN;
END;
$$ LANGUAGE plpgsql;

postgres=# SELECT * FROM foo(1);
┌─────┐
│ foo │
╞═════╡
│   1 │
└─────┘
(1 row)
相关问题