PostgreSQL 16中pg_cursors查询游标计数异常问题咨询
问题原因
PostgreSQL 16 调整了PL/pgSQL局部游标的可见性规则:你在过程里用DECLARE pg_cur CURSOR FOR ...声明的是局部游标,这类游标不会出现在系统视图pg_cursors里。但PostgreSQL 11里局部游标会被pg_cursors收录,所以原来靠查询pg_cursors判断的逻辑在16里失效,导致进不了循环。
解决方案
别再依赖pg_cursors做判断了,直接处理游标循环就行,或者用PL/pgSQL自带的游标状态属性:
方案1:删掉多余的检查,直接循环
改后的存储过程如下:
CREATE OR REPLACE PROCEDURE gis_in.pg_cur_test1() LANGUAGE 'plpgsql' AS $BODY$ DECLARE m_bref numeric; pg_cur CURSOR FOR SELECT id FROM emp; BEGIN OPEN pg_cur; FETCH pg_cur INTO m_bref; LOOP EXIT WHEN NOT FOUND; RAISE INFO 'm_bref is :,%', m_bref; FETCH pg_cur INTO m_bref; END LOOP; RAISE INFO 'Loop finished'; CLOSE pg_cur; END; $BODY$;
方案2:用游标属性判断是否打开(如果需要状态检查)
要是你确实得确认游标是否打开,用PL/pgSQL自带的%ISOPEN属性就行,比查pg_cursors靠谱:
CREATE OR REPLACE PROCEDURE gis_in.pg_cur_test1() LANGUAGE 'plpgsql' AS $BODY$ DECLARE m_bref numeric; pg_cur CURSOR FOR SELECT id FROM emp; BEGIN OPEN pg_cur; FETCH pg_cur INTO m_bref; IF pg_cur%ISOPEN THEN LOOP EXIT WHEN NOT FOUND; RAISE INFO 'm_bref is :,%', m_bref; FETCH pg_cur INTO m_bref; END LOOP; END IF; RAISE INFO 'Loop processing done'; CLOSE pg_cur; END; $BODY$;
额外优化:更简洁的游标写法
其实PL/pgSQL支持直接用FOR...IN遍历游标结果,不用手动打开、关闭游标,代码更简洁:
CREATE OR REPLACE PROCEDURE gis_in.pg_cur_test1() LANGUAGE 'plpgsql' AS $BODY$ DECLARE m_bref numeric; BEGIN FOR m_bref IN SELECT id FROM emp LOOP RAISE INFO 'm_bref is :,%', m_bref; END LOOP; RAISE INFO 'Loop completed'; END; $BODY$;
内容的提问来源于stack exchange,提问作者Gopal.anant
相关产品推荐
相关产品推荐

