想把UDF的返回结果保存在表里面,结果执行报错:
test=# insert into footest select * from f5();
ERROR: function cannot execute on a QE slice because it accesses relation "public.foo" (entry db 192.168.85.133:5432 pid=4212)
CONTEXT: SQL statement "select * from (select * from foo where fooid<5 limit 100)a"
PL/pgSQL function f5() line 3 at RETURN QUERY
函数定义:
原始定义:
test=# CREATE OR REPLACE FUNCTION f5() RETURNS SETOF foo AS
test-# BODY
test$# BEGIN
test$# RETURN query select * from foo;
test$# END;
test# BODY$
test-# LANGUAGE plpgsql;
修改为:
CREATE OR REPLACE FUNCTION f5(out fooid int,out foosubid int,out fooname text) RETURNS SETOF record AS
BODY
declare
row record;
BEGIN
for row in select * from foo where foo.fooid<5 loop
fooid:=row.fooid;
foosubid:=row.foosubid;
fooname:=row.fooname;
return next;
end loop;
return;
END;
BODY
LANGUAGE plpgsql;
根据高通的一个issue:
https://knowledge.broadcom.com/external/article/296772/why-we-got-error-like-function-cannot-ex.html
报错原因:
Greenplum is an MPP database, under such architecture, in most cases, the master (AKA: QD, Query Dispatcher) will dispatch the job to the segments (AKA: Query Executor), then gather the result from QE at the end.
one of the limitations of such architecture is, we can not execute non-SELECT statement queries on QE
An example use case that may trigger such error is like below:
the user would like to collect the AO compaction info based on the list inside a table.
gpadmin=# select oid,gp_toolkit.__gp_aovisimap_compaction_info(oid) from oid_list ;
ERROR: function cannot execute on a QE slice because it issues a non-SELECT statement (seg0 slice1 192.168.6.198:20000 pid=100663)
That is because:
-
the user table "oid_list" was distributed across all the segments
-
the query plan will first indentify the segmentID of target row of table "oid_list", the run the UDF __gp_aovisimap_compaction_info() on it
-
In this UDF there is an "EXECUTE" command inside it, Since EXECUTE is a non-select query, it can not run on QE, so get such error.
实验:
源表和目标表都必须为复制分布
目标表:
test=# create table footest(a text);
源表:
CREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT);
INSERT INTO foo VALUES (1, 2, 'three');
INSERT INTO foo VALUES (4, 5, 'six');
保留数据:
test=# insert into footest select distinct(f5) from (select f5() from gp_dist_random('foo'))a;
INSERT 0 2
test=# select * from footest;
a
(1,2,three)
(4,5,six)