PG迁移必读(十五):无缝迁移Sybase返回多结果集的存储过程
Barry Chen

前言

Sybase存储过程支持直接返回多个结果集,而PostgreSQL默认不支持这种行为。PostgreSQL可以通过在函数参数中定义多个游标,通过游标间接返回多个数据集。但这种方法会导致存储过程参数变化,并且如果游标很多,也会导致代码臃肿,降低开发效率。本文介绍一种新的方法,可以保持存储过程的参数不变,同时实现多结果集的返回,从而实现无缝迁移。

现有方案

以下是Sybase原存储过程,返回两个结果集:

Create Procedure proc2 AS

BEGIN

  select * from t1;

  select * from t2;

END

Sybase中过以下SQL调用存储过程:

exec proc2 

迁移时,现有方法需要定义返回两个游标参数的PostgreSQL存储函数:

Create Or Replace Procedure proc2( INOUT p1 refcursor, INOUT p2 refcursor

LANGUAGE PlPgSQL

AS $$ 

BEGIN

 open p1 for select * from t1;

 open p2 for select * from t2;

END;$$;

PostgreSQL中可以通过以下SQL调用存储过程:
DO $$ 

Declare 

  p1 refcursor;

  p2 refcursor;

BEGIN  

  CALL proc2( p1, p2);
END; $$ 

从上面代码可以看出,调用方式不一致了,PostgreSQL需要定义并传入更多的参数。下面介绍一种新方法,可以实现多结果集存储函数的无缝迁移。

新方案

为了在PostgreSQL中实现类似Sybase的多结果集返回,同时保持存储过程的参数不变,我们可以通过在存储过程内部定义游标名称,并在调用存储过程后通过游标名称获取数据。新的PostgreSQL代码如下:
Create Or Replace Procedure proc2(  ) 

LANGUAGE PlPgSQL

AS $$ 

Declare 

  p1 refcursor :='p1';

  p2 refcursor :='p2';

BEGIN

  open p1 for select * from t1;

  open p2 for select * from t2;

END;$$;

然后在PostgreSQL客户端通过以下方式调用存储过程:
CALL proc2(); 

FETCH ALL FROM p1;

FETCH ALL FROM p2;

通过对比可发现,新方法的调用方式与原Sybase是一致的,代码量也比原有方式要少,不用定义一堆的游标变量。

真实案例

CP8项目组有一个存储过程,返回170多个结果集。转换为PostgreSQL代码后,有170多个游标参数,这超出了PostgreSQL最大的100个参数的限制,导致运行失败。

 

 

后来按上述新方案更改后,成功编译运行。调用简化为

CALL proc_xxxx( ‘aaa’, ‘ppp’, ‘jjj’ )

简单明了,且参数与原Sybase一致。

总结

在将Sybase存储过程迁移到PostgreSQL时,通过在存储过程内部定义游标名称,可以实现多结果集的返回,同时保持存储过程的参数不变。这种方式不仅减少了迁移成本,还确保了与现有应用程序的兼容性。