You can directly export Oracle packages as Postgres Pro packages using ora2pgpro by setting the TYPE
configuration option to PACKAGE
. ora2pgpro finds the package, downloads and processes it, and reconstructs the abstract syntax tree (AST) representing the source code in the sources
directory under the current output directory. Then it generates equivalent code in PL/pgSQL in the result
directory under the current output directory. ora2pgpro aims to convert package code in such a way that the resulting package is as functional as possible and leaves WARNING
messages in code places that require programmer's attention.
All the package functions and procedures are public if there is no #private
modifier, and all the public package variables are listed under the #export
modifier of the __init__
function. If there are no public package variables, then __init__
will contain #export off
.
This is an example of the #export
and #import
modifiers:
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; --Here PKGA.z = 4 PERFORM dbms_output.put_line(x::varchar || y::varchar || z::varchar); END; $$ LANGUAGE PLPGSQL;
This is an example of the #private
modifier:
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;
This is how the function may be called:
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)
This is an example of an Oracle package.
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;
The resulting Postgres Pro package looks as follows.
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;