Экспорт пакетов

Используя ora2pgpro, можно напрямую экспортировать пакеты Oracle как пакеты Postgres Pro, если задать для типа экспорта TYPE значение PACKAGE. ora2pgpro находит пакет, скачивает и обрабатывает его, после чего восстанавливает абстрактное синтаксическое дерево (abstract syntax tree, AST), представляющее исходный код в каталоге sources в текущем выходном каталоге. Затем утилита генерирует аналогичный код на PL/pgSQL в каталоге result в текущем выходном каталоге. ora2pgpro стремится преобразовать код исходного пакета так, чтобы он был максимально работоспособен, а если разработчику необходимо обратить внимание на определённые места, оставляет в коде получившегося пакета сообщения WARNING.

Все пакетные функции и процедуры являются публичными, если отсутствует модификатор #private, а все публичные пакетные переменные перечислены в модификаторе #export функции __init__. Если публичных пакетных переменных нет, в функции __init__ прописывается #export off.

Пример с модификаторами #export и#import:

CREATE OR REPLACE FUNCTION PKGB.__INIT__() RETURNS VOID AS $$
#package
#import pkga
#export x, y
DECLARE
  x integer;
  y integer;
  z integer;
BEGIN
  x = 1;
  y = 2;
  z = PKGA.z; --Здесь PKGA.z = 4
  PERFORM dbms_output.put_line(x::varchar || y::varchar || z::varchar);
END;
$$ LANGUAGE PLPGSQL;

Пример с модификатором #private:

CREATE OR REPLACE FUNCTION PKGB.private_function(a integer) RETURNS integer AS $$
#package
#private
DECLARE
	b integer;
BEGIN
	b = a * 3;
	RETURN b;
END; $$ LANGUAGE PLPGSQL;

CREATE OR REPLACE FUNCTION PKGB.public_function(a integer) RETURNS integer AS $$
#package
BEGIN
	RETURN PKGB.private_function(a);
END; $$ LANGUAGE PLPGSQL;

Вызвать функцию можно так:

test=# select pkgb.private_function(2);
ERROR:  private package function or procedure pkgb.private_function(integer) called out of its package
CONTEXT:  PL/pgSQL function pkgb.private_function(integer)
test=# select pkgb.public_function(2);
NOTICE:  124
 public_function
-----------------
               6
(1 row)

Ниже приведён пример пакета из Oracle.

package body pkgc is
TYPE r_customer_type IS RECORD(
    customer_name varchar2(50),
    credit_limit number(10,2)
);

TYPE t_customer_type IS VARRAY(2)
    OF r_customer_type;

PROCEDURE VARRAY_TEST AS
    t_customers t_customer_type := t_customer_type();
    rec r_customer_type;
    tmp_string varchar2(2000);
BEGIN
    t_customers.EXTEND;
    t_customers(t_customers.LAST).customer_name := 'ABC Corp';
    t_customers(t_customers.LAST).credit_limit  := 10000;
    t_customers.EXTEND;
    t_customers(t_customers.LAST).customer_name := 'XYZ Inc';
    t_customers(t_customers.LAST).credit_limit  := 20000;
    tmp_string := 'The number of customers is ' || t_customers.COUNT;
    insert into pkgc_log (id, line) values (1, tmp_string);
    FOR indx in 1 .. t_customers.COUNT LOOP
        rec := t_customers(indx);
        tmp_string := 'RECORD: ' || rec.customer_name || ', ' || rec.credit_limit;
        insert into pkgc_log (id, line) values (1+ indx, tmp_string);
    END LOOP;
END;

BEGIN
  DELETE FROM pkgc_log;
END pkgc;

Пакет Postgres Pro после преобразования выглядит так:

BEGIN;
DROP SCHEMA IF EXISTS PKGC CASCADE;
CREATE SCHEMA PKGC;

CREATE TYPE PKGC.r_customer_type AS (
    customer_name varchar(50),
    credit_limit numeric(10,2)
);

CREATE DOMAIN PKGC.t_customer_type /*VARRAY(2)
    OF*/ PKGC.r_customer_type[];

CREATE OR REPLACE FUNCTION PKGC.__INIT__() RETURNS VOID AS $$
#package
#export off

BEGIN
  DELETE FROM pkgc_log;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE PROCEDURE PKGC.VARRAY_TEST() AS $$
#package
DECLARE
    /*WARNING: collection constructors are not supported.*/
    t_customers PKGC.t_customer_type /*:=*/ /*t_customer_type() /*WARNING: varray constructors are not supported.*/*/;
    rec PKGC.r_customer_type;
    tmp_string varchar(2000);
BEGIN
    t_customers = array_cat(t_customers, array_fill(NULL::PKGC.R_CUSTOMER_TYPE, ARRAY[1]));
    t_customers[array_upper(T_CUSTOMERS, 1)].customer_name = 'ABC Corp';
    t_customers[array_upper(T_CUSTOMERS, 1)].credit_limit  = 10000;

    t_customers = array_cat(t_customers, array_fill(NULL::PKGC.R_CUSTOMER_TYPE, ARRAY[1]));
    t_customers[array_upper(T_CUSTOMERS, 1)].customer_name = 'XYZ Inc';
    t_customers[array_upper(T_CUSTOMERS, 1)].credit_limit  = 20000;

    tmp_string = 'The number of customers is ' || array_length(T_CUSTOMERS, 1);
    insert into pkgc_log (id, line) values (1, tmp_string);

    FOR indx in 1 .. array_length(T_CUSTOMERS, 1) LOOP
        rec = t_customers[indx];
        tmp_string = 'RECORD: ' || rec.customer_name || ', ' || rec.credit_limit;
        insert into pkgc_log (id, line) values (1+ indx, tmp_string);
    END LOOP;
END; $$ LANGUAGE PLPGSQL;
/*end pkgc;*/

COMMIT;