Oracle 到 Postgres 的转换将游标作为参数传递
Oracle to Postgres conversion passing cursor as a parameter
我正在将 Oracle 存储过程转换为 Postgres。Oracle 使用输出参数
O_MTG_CURSOR OUT SYS_REFCURSOR
作为调用另一个存储过程的参数包含在内:
GET_MTG(O_MTG_CURSOR ,O_SQLCODE,O_SQLMSG );
当我尝试在 postgres 中调用相同的存储过程时,游标为空
CALL GET_MTG(O_MTG_CURSOR,O_SQLCODE,O_SQLMSG );
有没有什么方法可以将游标作为参数传递并使其 return 来自被调用存储过程的结果?
这个 Oracle 过程对其他存储过程进行了 10 次不同的调用,并用这些调用的结果填充输出游标。所以我需要能够在 postgres 中重复这个。
显示问题的最少代码
CREATE OR REPLACE PROCEDURE get_mtg (
i_mtg_id text,
i_lookup_type text,
i_agd text,
i_timestamp timestamp without time zone,
INOUT o_mtg_cursor refcursor DEFAULT NULL::refcursor,
INOUT o_dir_ocursor refcursor DEFAULT NULL::refcursor,
INOUT o_error_code integer DEFAULT 0,
INOUT o_error_msg character varying DEFAULT 'SUCCESS'::character varying)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
lookup_type_missing CHARACTER VARYING := 'lookup_type_missing';
mtg_id_missing CHARACTER VARYING := 'mtg_id_missing';
mtg_not_found CHARACTER VARYING := 'mt_not_found';
system_exception CHARACTER VARYING := 'system_exception';
dir_not_found CHARACTER VARYING := 'dir_not_found';
data_is_in_flux_state CHARACTER VARYING := 'data_is_in_flux_state';
l_agd_nbr CHARACTER VARYING(20);
BEGIN
RAISE NOTICE USING MESSAGE = '[GET_MTG] START';
o_error_code := 0;
o_error_msg := CONCAT_WS('', 'SUCESSFUL');
IF i_lookup_type IS NULL THEN
/* RAISE THE EXCEPTION THAT LOOK UP TYPE CANNOT BE NULL */
RAISE USING detail = lookup_type_missing, hint = 1;
ELSIF i_mtg_id IS NULL THEN
/* RAISE THE EXCEPTION THAT MTG_ID CANNOT BE NULL. */
RAISE USING detail = mtg_id_missing, hint = 1;
ELSE
RAISE NOTICE USING MESSAGE = '[GET_MTG] GET THE OUT PUT RESULT SET - START';
CALL GET_MTG_DIR(o_dir_cursor,O_ERROR_CODE,O_ERROR_MSG );
CALL GET_MTG_DTL(o_mtg_cursor,O_ERROR_CODE,O_ERROR_MSG );
END IF;
RAISE NOTICE USING MESSAGE = '[GET_MTG] END';
EXCEPTION
WHEN raise_exception THEN
DECLARE
exc$name CHARACTER VARYING;
exc$code CHARACTER VARYING;
BEGIN
GET STACKED DIAGNOSTICS exc$name := pg_exception_detail,
exc$code := pg_exception_hint;
IF exc$name = mtg_id_missing THEN
o_error_code := 101;
o_error_msg := 'ERROR 101.1 : I_MTG_ID CAN NOT BE NULL : RESOLUTION : PASS ''AGD_NBR''';
END IF;
IF exc$name = mtg_not_found THEN
o_error_code := 101;
o_error_msg := CONCAT_WS('', 'ERROR 101.2 : MTG CANNOT BE FOUND : ', i_agd_nbr, ' : RESOLUTION : CHECK THE MTG TABLE');
END IF;
IF exc$name = dir_not_found THEN
o_error_code := 102;
o_error_msg := CONCAT_WS('', 'ERROR 102.1 : DIR IS EMPTY FOR PREF TYPE ''Z'' ON : ', i_mtg_id, ' & ', l_agd_nbr, ' : RESOLUTION : ESCALATE TO SYSADMIN');
END IF;
IF exc$name = data_is_in_flux_state THEN
o_error_code := 501;
o_error_msg := CONCAT_WS('', 'ERROR 501.1 : AGD/DIR/PREF are in flux state - ', i_mtg_id, ', ', l_agd_nbr, ' : RESOLUTION : ESCALATE TO SYSADMIN ');
END IF;
IF exc$name = system_exception THEN
o_error_code := SQLSTATE * - 1;
o_error_msg := CONCAT_WS('', '[GET_MTG] SYSTEM EXCEPTION OCCURED : ', substr(SQLERRM, 1, 200));
END IF;
END;
WHEN no_data_found THEN
o_error_code := 100;
o_error_msg = 'Error: ' || SQLSTATE || ' - ' || SQLERRM;
WHEN others THEN
o_error_code = -1;
o_error_msg = 'Error: ' || SQLSTATE || ' - ' || SQLERRM;
END;
$BODY$;
感谢您的意见,但我不确定我是否理解您的问题。也许我的回答会有帮助。
这是一个如何将 refcursor 与存储过程一起使用的示例。
这里是源代码:
create table t(x int, t text);
insert into t values(1, 'ONE');
insert into t values(2, 'TWO');
--
create or replace procedure prc3 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
open l_rc for select * from t;
p_rc = l_rc;
end;
$$ language plpgsql;
--
\echo
--
create or replace procedure prc2 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
call prc3(l_rc);
p_rc = l_rc;
end;
$$ language plpgsql;
--
\echo
--
create or replace procedure prc1()
as $$
declare
v refcursor;
vx int;
vy text;
begin
call prc2(v);
fetch next from v into vx, vy;
raise notice 'vx=% vy=%', vx, vy;
end
$$ language plpgsql;
--
call prc1();
这是一个执行:
create table t(x int, t text);
CREATE TABLE
insert into t values(1, 'ONE');
INSERT 0 1
insert into t values(2, 'TWO');
INSERT 0 1
create or replace procedure prc3 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
open l_rc for select * from t;
p_rc = l_rc;
end;
$$ language plpgsql;
CREATE PROCEDURE
create or replace procedure prc2 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
call prc3(l_rc);
p_rc = l_rc;
end;
$$ language plpgsql;
CREATE PROCEDURE
create or replace procedure prc1()
as $$
declare
v refcursor;
vx int;
vy text;
begin
call prc2(v);
fetch next from v into vx, vy;
raise notice 'vx=% vy=%', vx, vy;
end
$$ language plpgsql;
CREATE PROCEDURE
call prc1();
psql:trc.sql:44: NOTICE: vx=1 vy=ONE
CALL
我正在将 Oracle 存储过程转换为 Postgres。Oracle 使用输出参数
O_MTG_CURSOR OUT SYS_REFCURSOR
作为调用另一个存储过程的参数包含在内:
GET_MTG(O_MTG_CURSOR ,O_SQLCODE,O_SQLMSG );
当我尝试在 postgres 中调用相同的存储过程时,游标为空
CALL GET_MTG(O_MTG_CURSOR,O_SQLCODE,O_SQLMSG );
有没有什么方法可以将游标作为参数传递并使其 return 来自被调用存储过程的结果? 这个 Oracle 过程对其他存储过程进行了 10 次不同的调用,并用这些调用的结果填充输出游标。所以我需要能够在 postgres 中重复这个。
显示问题的最少代码
CREATE OR REPLACE PROCEDURE get_mtg (
i_mtg_id text,
i_lookup_type text,
i_agd text,
i_timestamp timestamp without time zone,
INOUT o_mtg_cursor refcursor DEFAULT NULL::refcursor,
INOUT o_dir_ocursor refcursor DEFAULT NULL::refcursor,
INOUT o_error_code integer DEFAULT 0,
INOUT o_error_msg character varying DEFAULT 'SUCCESS'::character varying)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
lookup_type_missing CHARACTER VARYING := 'lookup_type_missing';
mtg_id_missing CHARACTER VARYING := 'mtg_id_missing';
mtg_not_found CHARACTER VARYING := 'mt_not_found';
system_exception CHARACTER VARYING := 'system_exception';
dir_not_found CHARACTER VARYING := 'dir_not_found';
data_is_in_flux_state CHARACTER VARYING := 'data_is_in_flux_state';
l_agd_nbr CHARACTER VARYING(20);
BEGIN
RAISE NOTICE USING MESSAGE = '[GET_MTG] START';
o_error_code := 0;
o_error_msg := CONCAT_WS('', 'SUCESSFUL');
IF i_lookup_type IS NULL THEN
/* RAISE THE EXCEPTION THAT LOOK UP TYPE CANNOT BE NULL */
RAISE USING detail = lookup_type_missing, hint = 1;
ELSIF i_mtg_id IS NULL THEN
/* RAISE THE EXCEPTION THAT MTG_ID CANNOT BE NULL. */
RAISE USING detail = mtg_id_missing, hint = 1;
ELSE
RAISE NOTICE USING MESSAGE = '[GET_MTG] GET THE OUT PUT RESULT SET - START';
CALL GET_MTG_DIR(o_dir_cursor,O_ERROR_CODE,O_ERROR_MSG );
CALL GET_MTG_DTL(o_mtg_cursor,O_ERROR_CODE,O_ERROR_MSG );
END IF;
RAISE NOTICE USING MESSAGE = '[GET_MTG] END';
EXCEPTION
WHEN raise_exception THEN
DECLARE
exc$name CHARACTER VARYING;
exc$code CHARACTER VARYING;
BEGIN
GET STACKED DIAGNOSTICS exc$name := pg_exception_detail,
exc$code := pg_exception_hint;
IF exc$name = mtg_id_missing THEN
o_error_code := 101;
o_error_msg := 'ERROR 101.1 : I_MTG_ID CAN NOT BE NULL : RESOLUTION : PASS ''AGD_NBR''';
END IF;
IF exc$name = mtg_not_found THEN
o_error_code := 101;
o_error_msg := CONCAT_WS('', 'ERROR 101.2 : MTG CANNOT BE FOUND : ', i_agd_nbr, ' : RESOLUTION : CHECK THE MTG TABLE');
END IF;
IF exc$name = dir_not_found THEN
o_error_code := 102;
o_error_msg := CONCAT_WS('', 'ERROR 102.1 : DIR IS EMPTY FOR PREF TYPE ''Z'' ON : ', i_mtg_id, ' & ', l_agd_nbr, ' : RESOLUTION : ESCALATE TO SYSADMIN');
END IF;
IF exc$name = data_is_in_flux_state THEN
o_error_code := 501;
o_error_msg := CONCAT_WS('', 'ERROR 501.1 : AGD/DIR/PREF are in flux state - ', i_mtg_id, ', ', l_agd_nbr, ' : RESOLUTION : ESCALATE TO SYSADMIN ');
END IF;
IF exc$name = system_exception THEN
o_error_code := SQLSTATE * - 1;
o_error_msg := CONCAT_WS('', '[GET_MTG] SYSTEM EXCEPTION OCCURED : ', substr(SQLERRM, 1, 200));
END IF;
END;
WHEN no_data_found THEN
o_error_code := 100;
o_error_msg = 'Error: ' || SQLSTATE || ' - ' || SQLERRM;
WHEN others THEN
o_error_code = -1;
o_error_msg = 'Error: ' || SQLSTATE || ' - ' || SQLERRM;
END;
$BODY$;
感谢您的意见,但我不确定我是否理解您的问题。也许我的回答会有帮助。
这是一个如何将 refcursor 与存储过程一起使用的示例。
这里是源代码:
create table t(x int, t text);
insert into t values(1, 'ONE');
insert into t values(2, 'TWO');
--
create or replace procedure prc3 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
open l_rc for select * from t;
p_rc = l_rc;
end;
$$ language plpgsql;
--
\echo
--
create or replace procedure prc2 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
call prc3(l_rc);
p_rc = l_rc;
end;
$$ language plpgsql;
--
\echo
--
create or replace procedure prc1()
as $$
declare
v refcursor;
vx int;
vy text;
begin
call prc2(v);
fetch next from v into vx, vy;
raise notice 'vx=% vy=%', vx, vy;
end
$$ language plpgsql;
--
call prc1();
这是一个执行:
create table t(x int, t text);
CREATE TABLE
insert into t values(1, 'ONE');
INSERT 0 1
insert into t values(2, 'TWO');
INSERT 0 1
create or replace procedure prc3 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
open l_rc for select * from t;
p_rc = l_rc;
end;
$$ language plpgsql;
CREATE PROCEDURE
create or replace procedure prc2 (inout p_rc refcursor)
as $$
declare
l_rc refcursor;
begin
call prc3(l_rc);
p_rc = l_rc;
end;
$$ language plpgsql;
CREATE PROCEDURE
create or replace procedure prc1()
as $$
declare
v refcursor;
vx int;
vy text;
begin
call prc2(v);
fetch next from v into vx, vy;
raise notice 'vx=% vy=%', vx, vy;
end
$$ language plpgsql;
CREATE PROCEDURE
call prc1();
psql:trc.sql:44: NOTICE: vx=1 vy=ONE
CALL