Используя 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;