转换Oracle存储程序使用REF_CURSOR并包的全球变Postgresql或MySQL
-
20-08-2019 - |
题
这包使用两个独特的特征Oracle、REF_CURSOR和一揽子全球变量。我要港口的功能Oracle Postgresql或MySQL.
PACKAGE tox IS
/*=======================*/
g_spool_key spool.key%TYPE := NULL;
TYPE t_spool IS REF CURSOR RETURN spool%ROWTYPE;
/*=======================*/
PROCEDURE begin_spool;
/*=======================*/
PROCEDURE into_spool
(
in_txt IN spool.txt%TYPE
);
/*=======================*/
PROCEDURE reset_spool;
/*=======================*/
FUNCTION end_spool
RETURN t_spool;
/*=======================*/
FUNCTION timestamp
RETURN VARCHAR2;
/*=======================*/
END tox;
PACKAGE BODY tox
IS
/*========================================================================*/
PROCEDURE begin_spool
AS
/*=======================*/
BEGIN
/*=======================*/
SELECT
key.NEXTVAL
INTO
g_spool_key
FROM
DUAL;
/*=======================*/
END begin_spool;
/*========================================================================*/
PROCEDURE into_spool
(
in_txt IN spool.txt%TYPE
)
AS
/*=======================*/
BEGIN
/*=======================*/
INSERT INTO
spool
VALUES
(
g_spool_key,
in_txt,
seq.NEXTVAL
);
/*=======================*/
END into_spool;
/*========================================================================*/
PROCEDURE reset_spool
AS
/*=======================*/
BEGIN
/*=======================*/
DELETE
spool
WHERE
key = g_spool_key;
COMMIT;
begin_spool;
/*=======================*/
END reset_spool;
/*========================================================================*/
FUNCTION end_spool
RETURN t_spool
AS
v_spool t_spool;
/*=======================*/
BEGIN
/*=======================*/
COMMIT;
OPEN v_spool FOR
SELECT
*
FROM
spool
WHERE
key = g_spool_key
ORDER BY
seq;
RETURN v_spool;
/*=======================*/
END end_spool;
/*========================================================================*/
FUNCTION timestamp
RETURN VARCHAR2
AS
/*-----------------------*/
v_result VARCHAR2(14);
/*=======================*/
BEGIN
/*=======================*/
SELECT
TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')
INTO
v_result
FROM
DUAL;
RETURN v_result;
/*=======================*/
END timestamp;
/*========================================================================*/
END tox;
你可以产生相当于代码?Postgresql?MySQL?
注:Oracle码线的安全。这是一个关键要素。
解决方案
<强>的PostgreSQL 8.3 强>
PostgreSQL中的问题是缺乏全局(或封装)的变量,使得部件具有与首先被创建的临时表来解决。它的其余部分是相当容易的。
如果你是认真的在移植应用到PostgreSQL或MySQL,我建议(根据我至少:)编码时,你并不因为他们是坏的实践中使用全局变量)
但是不管怎样,这里是代码:
这具有运行功能前,存在:
create table spool (key integer, txt varchar(2048), seq integer);
create sequence s_key;
create sequence s_seq;
create schema tox;
create temp table globals (name varchar(10), value varchar(100), primary key(name));
被投入在模式TOX的功能以模拟程序包。
create or replace function tox.get_variable(var_name varchar) returns varchar as $$
declare
ret_val varchar(100);
begin
select value into ret_val from globals where name = var_name;
return ret_val;
end
$$ language plpgsql;
create or replace function tox.set_variable(var_name varchar, value anyelement) returns void as $$
begin
delete from globals where name = var_name;
insert into globals values(var_name, value);
end;
$$ language plpgsql;
create or replace function tox.begin_spool() returns integer as $$
begin
perform tox.set_variable('key', nextval('s_key')::varchar);
return tox.get_variable('key');
end;
$$ language plpgsql;
create or replace function tox.reset_spool() returns integer as $$
begin
delete from spool where key = tox.get_variable('key')::integer;
return tox.begin_spool();
end;
$$ language plpgsql;
create or replace function tox.into_spool(in_txt spool.txt%TYPE) returns void as $$
begin
insert into spool values(tox.get_variable('key')::integer, in_txt, nextval('s_seq'));
end;
$$ language plpgsql;
create or replace function tox.end_spool(refcursor) returns refcursor as $$
declare
begin
open $1 for select * from spool where key = tox.get_variable('key')::integer order by seq;
return $1;
end;
$$ language plpgsql;
create or replace function tox.test(txt varchar(100)) returns setof spool as $$
declare
v_spool_key integer;
cnt integer;
begin
v_spool_key = tox.begin_spool();
for cnt in 1..10 loop
perform tox.into_spool(txt || cnt);
end loop;
perform tox.end_spool('spool_cursor');
return query fetch all from spool_cursor;
end;
$$ language plpgsql;
要测试,只是一切后,运行此已创建。
select * from tox.test('Test');
其他提示
Mysql:
- 为ref_cursor你可以只用一个常规的选择在一个过程。Mysql有一个隐含的结果设置返回存储的过程如果发出一个选择的发言。看到我的回答 在这里,.
- 包全球可变的,你可以把它放在一个表,但它似乎从你的代码,这是一个序列,所以它可以替换为一个auto_increment领域。这应该很简单。
这将帮助如果你可以发布的定义你的卷表中的问题。然后我大概可以提供精确的代码mysql.
我有一个很难理解一些事情在你的代码。它看起来就像你有两个序列表,但其中只有一个是真正的AUTO_INCREMENT列。
在MySQL的AUTO_INCREMENT仅在表中的一列允许的。你有没有考虑做其他列的外键到另一个表的自动递增列?
全局变量是棘手的,因为MySQL没有它们。我认为唯一的解决办法是将其存储在一个表中的标,然后你的数据与外键关联到它。
最后,返回一个REF CURSOR是容易的,正如我在前面的回答中指出。在链路提供(以不同的答案),你可以看到一个代码示例。
下面是与MySQL 5.1.30测试的溶液。
关于你的线程安全的要求,MySQL的用户可变机制应该有所帮助。这使您可以 SET
一个变量,其状态限于当前的会话。其他会话还可以创建由相同的名称的变量,并且在它保持一个不同的值。
我的线程安全假设你的意思是这样的 - 会话作用域的状态。因为你不能真正在数据库中更细粒度的线程安全状态。你的应用程序的每个线程都必须有它自己的会话到数据库中。
有在MySQL没有封装,所以用户变量是全局的会话。这种情况发生使用相同的名称的变量另一个存储过程将发生冲突。
CREATE TABLE spool (
`key` INT,
txt VARCHAR(2048),
seq INT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE spool_key (
`key` INT AUTO_INCREMENT PRIMARY KEY
);
DELIMITER $$
CREATE PROCEDURE begin_spool ()
BEGIN
DELETE FROM spool_key;
INSERT INTO spool_key (`key`) VALUES (DEFAULT);
SET @sp_key = LAST_INSERT_ID();
END $$
CREATE PROCEDURE into_spool(IN in_txt VARCHAR(2048))
BEGIN
INSERT INTO spool (`key`, txt, seq) VALUES
(@sp_key, in_txt, DEFAULT);
END $$
CREATE PROCEDURE reset_spool()
BEGIN
DELETE spool FROM spool JOIN spool_key USING (`key`);
CALL begin_spool();
END $$
CREATE PROCEDURE end_spool()
BEGIN
SELECT *
FROM spool JOIN spool_key USING (`key`)
ORDER BY seq;
END $$
DELIMITER ;
CALL begin_spool();
CALL into_spool('now is the time');
CALL into_spool('for all good men');
CALL end_spool();
CALL reset_spool();
CALL into_spool('to come to the aid');
CALL into_spool('of their country');
CALL end_spool();
DROP FUNCTION IF EXISTS fmt_timestamp;
CREATE FUNCTION fmt_timestamp() RETURNS CHAR(14)
RETURN DATE_FORMAT(SYSDATE(), '%Y%m%d%H%i%s');
SELECT fmt_timestamp();