Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

possibility to force transformation procedures to functions #1830

Open
okbob opened this issue Oct 20, 2024 · 11 comments
Open

possibility to force transformation procedures to functions #1830

okbob opened this issue Oct 20, 2024 · 11 comments

Comments

@okbob
Copy link
Contributor

okbob commented Oct 20, 2024

My customer reported, so there is not possibility to ensure old behaviour of transformation procedures on modern postgres.

PG_SUPPORTS_PROCEDURE is implicitly set for PostgreSQL v11+. Can be nice to have some option that forces old behaviour.

@darold
Copy link
Owner

darold commented Oct 21, 2024

Hi Pavel,

Normally you just have to set PG_VERSION to the version of the PostgreSQL server. If you set it to 10 then PG_SUPPORTS_PROCEDURE will be disabled.

@okbob
Copy link
Contributor Author

okbob commented Oct 21, 2024 via email

@darold
Copy link
Owner

darold commented Oct 21, 2024

Commit 0a22650 might support overriding of the PG_VERSION automatic adjustment of these PG_SUPPORT_* variables.

If they are defined in the configuration file, they take precedence onto the PG_VERSION behavior, whether they are disabled or enabled.

@okbob
Copy link
Contributor Author

okbob commented Oct 21, 2024 via email

@okbob
Copy link
Contributor Author

okbob commented Oct 27, 2024

My customer did some tests and, unfortunately, reported few issues:

  1. Although the procedure is converted to function, it is called by CALL statement instead SELECT
  2. Transformed function use strange OUT extra_param OPAQUE argument. OPAQUE pseudotype was removed in PostgreSQL 12

Oracle:

create or replace procedure CO_ZNAK (
mINTERFS IN VARCHAR2,
mCISLO in OUT NUMBER ,
mTEXT in OUT VARCHAR2 )

IS

--i NUMBER;
 
--akt NUMBER;
mZnak CHAR(1);


begin
   if mINTERFS is not NULL then
   ---
   FOR i IN 1..LENGTH(mINTERFS)
   LOOP
     mZnak := SUBSTR(mINTERFS , i,1 );

    
    IF mZnak IN ( '0','1','2','3','4','5','6','7','8','9','0' ) THEN    
        mCISLO :=TO_NUMBER(TO_CHAR(mCISLO)||mZnak);     
     else   
       mTEXT :=mTEXT||mZnak;     
     end if;  
     
   END LOOP;
   end if;
   
end CO_ZNAK;

Older ora2pg

CREATE OR REPLACE FUNCTION co_znak ( mINTERFS text, mCISLO INOUT numeric , mTEXT INOUT text ) AS $body$
DECLARE


--i NUMBER;
 
--akt NUMBER;
mZnak char(1);


BEGIN
   if mINTERFS is not NULL then
   ---
   FOR i IN 1..LENGTH(mINTERFS)
   LOOP
     mZnak := SUBSTR(mINTERFS , i,1 );


    IF mZnak IN ( '0','1','2','3','4','5','6','7','8','9','0' ) THEN    
        mCISLO :=(TO_CHAR(mCISLO)||mZnak)::numeric;
     else   
       mTEXT :=mTEXT||mZnak;
     end if;
     
   END LOOP;
   end if;

end;
$body$
LANGUAGE PLPGSQL
SECURITY DEFINER
;

Current Ora2pg

CREATE OR REPLACE FUNCTION co_znak ( mINTERFS text, mCISLO INOUT bigint , mTEXT INOUT text , OUT extra_param OPAQUE) RETURNS record AS $body$
DECLARE


--i NUMBER;
 
--akt NUMBER;
mZnak char(1);


BEGIN
   if (mINTERFS AND mINTERFS::text <> '') then
   ---
   FOR i IN 1..LENGTH(mINTERFS)
   LOOP
     mZnak := SUBSTR(mINTERFS , i,1 );


    IF mZnak IN ( '0','1','2','3','4','5','6','7','8','9','0' ) THEN    
        mCISLO :=(TO_CHAR(mCISLO)||mZnak)::numeric;
     else   
       mTEXT :=mTEXT||mZnak;
     end if;
     
   END LOOP;
   end if;

end;

$body$
LANGUAGE PLPGSQL
SECURITY DEFINER
;

@darold
Copy link
Owner

darold commented Oct 28, 2024

Thanks Pavel. Commit 4d1696c might solve this issue.

@okbob
Copy link
Contributor Author

okbob commented Dec 3, 2024

I have check report from my customer. He found still one issue. When procedure has more OUT arguments, then migration is ok, but when procedure has just one OUT argument, then there is a problem, because ora2pg produces function like

CREATE OR REPLACE FUNCTION akt_abo_skupina ( mID_PARABOVYS PARABOVYS.ID_PARABOVYS%TYPE , mPocChyb OUT numeric ) RETURNS record AS $body$

And this doesn't work

(2024-12-03 18:57:47) postgres=# create or replace function foo(x out int) returns int as $$ begin x := 10; end $$ language plpgsql;
CREATE FUNCTION
(2024-12-03 18:58:25) postgres=# select foo();
┌─────┐
│ foo │
╞═════╡
│  10 │
└─────┘
(1 row)

(2024-12-03 18:58:32) postgres=# create or replace function foox(x out int) returns record as $$ begin x := 10; end $$ language plpgsql;
ERROR:  function result type must be integer because of OUT parameters

@darold
Copy link
Owner

darold commented Dec 4, 2024

Hi Pavel,

Here is an Oracle function with a single out parameter and e return value:

function fct_test(p1 varchar, p2 out number) return number
as 
DECLARE
        v1 number := 100;
BEGIN
  p2 := 10;
  return v1;
END fct_test;

It is correctly translated by ora2pg into

CREATE OR REPLACE FUNCTION fct_test (p1 text, p2 out bigint, OUT extra_param bigint) RETURNS record AS $body$
DECLARE

        v1 bigint := 100;

BEGIN
  p2 := 10;
  extra_param := v1;
  RETURN;
END;
$body$
LANGUAGE PLPGSQL
 STABLE;

Then when using it it returns the right result:

gilles=# DO $$                                                                                                        
DECLARE
    a bigint;
    b bigint;
BEGIN
    SELECT * FROM fct_test('hello') INTO a, b;
    RAISE NOTICE 'a=%, b=%', a, b;
END;                
$$;
NOTICE:  a=10, b=100
DO

@darold
Copy link
Owner

darold commented Dec 4, 2024

Note that I have fix a wrong translation of OUT to INOUT in new commit cbb61c6

@darold
Copy link
Owner

darold commented Dec 4, 2024

With this commit an Oracle function defined as follow:

function fct_test(p2 out number)
as 
BEGIN 
  p2 := 10;
END fct_test;

is translated into

CREATE OR REPLACE FUNCTION fct_test (p2 out bigint) AS $body$
BEGIN
  p2 := 10;
END;
$body$
LANGUAGE PLPGSQL
 STABLE;

which returns the expected result:

gilles=# DO $$                   
DECLARE
a bigint;
BEGIN
SELECT * FROM fct_test() INTO a;
RAISE NOTICE 'a=%', a;
END;
$$;
NOTICE:  a=10
DO

@okbob
Copy link
Contributor Author

okbob commented Dec 4, 2024

Unfortunately, it is not fixed (on procedures). It was not when Oracle's procedures are converted to postgres functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants