Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Ionut.

Asked: September 03, 2024 - 3:33 pm UTC

Last updated: September 06, 2024 - 1:48 pm UTC

Version: 12.2.0.1.0

Viewed 1000+ times

You Asked

Hello Tom,

I am trying to inline a function when using a MERGE statement and I am not sure if it is working as no error is thrown.
Here is my code:

CREATE OR REPLACE PACKAGE my_pkg
IS
    FUNCTION my_fnc ( p1 VARCHAR2
                    , p2 VARCHAR2) RETURN VARCHAR2;
END my_pkg;
/
CREATE OR REPLACE PACKAGE BODY my_pkg
IS
    FUNCTION my_fnc ( p1 VARCHAR2
                    , p2 VARCHAR2) RETURN VARCHAR2
    IS
    BEGIN
        RETURN p1 || '-' || p2;
    END my_fnc;
END my_pkg;
/
CREATE OR REPACE PROCEURE my_prc
IS
    TYPE t_type IS TABLE OF my_tab2%ROWTYPE;
    v_nt t_type;
    v_colx my_tab2.colx%TYPE;
BEGIN
    -- version 1
    PRAGMA INLINE (my_fnc, 'YES');
    MERGE INTO my_tab1 a
    USING (SELECT col1
                , col2
                , my_pkg.my_fnc(col3, col4) colx
                , col5
                , col6
             FROM my_tab2
           WHERE 1 = 1) b -- the condition doesn't mather
       ON (a.col1 = b.col1 AND a.col2 = b.col2 AND a.colx = b.colx)
    WHEN MATCHED THEN
        UPDATE SET a.col5 = b.col5
                 , a.col6 = b.col6
    WHEN NOT MATCHED THEN
        INSERT ( col1
               , col2
               , colx
               , col5
               , col6);
    COMMIT;
    --
    -- version 2
    SELECT col1
         , col2
         , my_pkg.my_fnc(col3, col4) colx
         , col5
         , col6
    BULK COLLECT INTO v_nt
    FROM my_tab2;
    
    FORALL i IN v_nt.FIRST .. v_nt.LAST
        PRAGMA INLINE (my_fnc, 'YES');
        v_colx := my_pkg.my_fnc(col3, col4);
        
        MERGE INTO my_tab1 a
        USING (SELECT v_nt(i).col1 col1
                    , v_nt(i).col2 col2
                    , v_colx
                    , v_nt(i).col5 col5
                    , v_nt(i).col6 col6
                 FROM dual) b -- the condition doesn't mather
       ON (a.col1 = b.col1 AND a.col2 = b.col2 AND a.colx = b.colx)
    WHEN MATCHED THEN
        UPDATE SET a.col5 = b.col5
                 , a.col6 = b.col6
    WHEN NOT MATCHED THEN
        INSERT ( col1
               , col2
               , colx
               , col5
               , col6);
END my_prc;


Now, my questions are: can any version be inlinied?
Version 1 could not be inlined because it is not preceding any of the statements mention in ORacle documentation ( https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/plsql-optimization-and-tuning.html#GUID-2E78813E-CF29-409D-9F8B-AA24B294BFA2 )
Version 1 could not be inlined because, also the invoked and invoking subprograms are not in the same program unit
(it is not very clear what means "same program unit")
Version 2 could be inlined because it is using the assignment statement?
Version 2 could not be inlined because the invoked and invoking subprograms are not in the same program unit

Thank you,
Ionut Preda.

and Chris said...

Inlining only happens to calls in PL/SQL. You're calling the function from SQL. So the calls can't be inlined.

This could be inlined:

PRAGMA INLINE (my_fnc, 'YES');
v_colx := my_pkg.my_fnc(col3, col4);


...if it wasn't inside a FORALL statement.

What exactly are you trying to achieve here and why?

If it's to avoid the PL/SQL<>SQL context switch you'll have to copy logic into the SQL statement itself.

Until you get to 23ai :)

This adds the automatic SQL transpiler. This can extract expressions from PL/SQL calls in SQL into the SQL statement itself.

To enable it set this parameter:

alter session set sql_transpiler = on;


This will then transpiler all eligible functions. Currently, functions will not get transpiled if they contain any PL/SQL (e.g. %type variables, function calls) or SQL statements.

For more details see our discuss of this in last month's SQL Office hours



Or you can read more in this post by Ulrike Schwinn

https://blogs.oracle.com/coretec/post/sql-transpiler-in-23c

Rating

  (3 ratings)

Comments

Ionut Preda, September 04, 2024 - 3:29 pm UTC

Hello Chris,

Many thanks for your time.
The inlining start from an issue I encounter after migrating from On Premis to OCI.
More exactly, I have a procedure with many cases where the concatenation from function body are performed (depending by some variables) and for an unknown reason, at a certain branch, the concatenation returns NULL, which should not because there should be, at least the '-' character.

For this, I decided to move the concatenation, separately into a function and for few days, the procedure ran OK.
But it was not enough for me and I wanted to inline the function, for increasing the performance (I am not sure if by inlineing, I will turn back from where I started)

All the discussion would not be necessary if I would be able to find the root cause of the NULL.
Did you hear any other similar complains about NULL-ing a value without any reason?

Best,
Ionut Preda.
Chris Saxon
September 04, 2024 - 5:14 pm UTC

I don't know why a value would be unexpectedly null. Submit a new question showing the code and explaining what's changed and we can help you figure it out.

A reader, September 05, 2024 - 7:02 am UTC

Unfortunately, I am not allowed to provide the code but nothing was changed into the code.
The only modification made was the migration from On Premise to OCI.
Also the problem do not occur everywhere a similar concatenation is performed, just at one place into the procedure.
Chris Saxon
September 05, 2024 - 1:04 pm UTC

Understand you can't share real code - can you make a test case that reproduces the problem though?

Ionut Preda, September 05, 2024 - 1:56 pm UTC

Neither can do that because it happens very rare (only one environment out of 35).
One more important different thing is that if I manually execute the MERGE SQL statement the issue does not occur but if I execute the procedure which contains that MERGE piece of code, the error is rasing.
Chris Saxon
September 06, 2024 - 1:48 pm UTC

I don't know what would cause this and with an example there's little help I can give. Reach out to support and share full details with them so they can help investigate.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library