Skip to main content

Wait, did the PL/SQL compiler just REMOVE my code?

The PL/SQL compiler does more than compile - it also:
  1. automatically optimizes your code to run faster
  2. offers advice in the form of compile-time warnings to improve the quality and/or performance of your code
  3. allows you to conditionally include or exclude portions of your code for compilation
That's just fantastic - but it can now and then result in some confusing moments for the Oracle Database developer (well, at least this developer).

Recently, I was looking over the warnings I had gotten for a new package I'd written and saw this:


Wait - my "procedure" user_goals_cur was removed?

I could tell by the name that it was not a procedure - it was a cursor. So clearly the warning message hasn't been customized to the type of code removed. OK, that's no big deal - I can deal with that. 

But when I see the PLW-06006 warning, it has meant that I'd written a nested subprogram in a procedure or function but it was no longer used. It was superfluous code that should have been removed - so the compiler removed it for me (from the compiled code, not my source code).

But a cursor? Did I declare a cursor and then not use it? Entirely possible. 

So I opened up the package body and saw this:


As I expect you can see, the cursor is used. OK, now I was worried. It was removing code that I was using? How could that make any sense?

Well, you know what they say: Trust The Compiler. And trust people you know are way smarter than you - in this case, the PL/SQL development team.

So rather than panicking about the removal of essential code, I went back and took a closer look at the warnings report. And this time I noticed the second warning that referenced the same "USER_GOALS_CUR":


The cursor was inlined! Now this was interesting news for two reasons:
  1. I hadn't even realized that the compiler performed the inlining operation on cursors.
  2. It made me think that perhaps the inlining was somehow related to the removal of the cursor.
But first for those who are unfamiliar with the inlining feature, I will take a moment to explain.

Suppose I have a procedure defined as follows:

PROCEDURE p
IS
   FUNCTION f RETURN NUMBER
   IS BEGIN ... END;
BEGIN
   IF f() THEN ...
END;

When f is executed at runtime, PL/SQL spends a small amount of time finding the code for f. If you'd like to avoid this overhead, you can ask the compiler to inline the function. This means that when you compile your program, the invocation of a subprogram is replaced by the code itself. Your compiled code size increases, but the runtime performance is faster.

We recommend that you set your PL/SQL optimization level to 3 (default is 2) to take full advantage of this feature. You an also selectively request to inline or disable inlining with the PRAGMA INLINE statement. Check the doc for lots more information on inlining.

So when you see the PLW-06006 warning, you know that inlining optimization is enabled and has been put into effect.

And that's when the light bulb goes off in my head and I realize:
  1. A cursor really is no different than a function. You "pass in" bind variables and "return" one or more values via the SELECT list. So the compiler doesn't just inline procedures and functions. It inlines cursors, too! How cool is that?
  2. Once the cursor (or procedure or function) has been inlined, there is no reason to keep it defined as a cursor or subprogram in the declaration section. So the compiler removes it.
That all makes perfect sense, but, gee, that's also kind of confusing. False alarm, and all that. 

The bottom line is that the PL/SQL compiler will "remove" code (leave it "behind" in the source code and not move it to the compiled code) only when it is truly not used or not needed to execute your code.

So remember:

Trust your compiler.

But verify your understanding of what it is doing.









Comments

  1. Trust the compiler, but, still not sure what is the advantage of inline function here. Did we avoid the context switch using inline function ( I am sure no), What different it is when we open a cursor and return the value returned by SQL engine to the PLSQL record, compared to using a function which in turn calls the SQL which does the same thing.

    ReplyDelete
  2. Context switches do not come into play here, since there is no switch between the SQL and PL/SQL engines. Instead, inlining avoids the overhead of looking up the code block for the procedure or function or (as it turns out) cursor. Instead, the code is simple "there", inline in the current block.

    ReplyDelete
  3. If you in-line a procedure or function you never have to allocate a stack frame for it. I.e. a local scope for the procedure's state: variables, etc. And then you don't have to remove that stack frame after exiting the procedure/function.

    This can be a significant win if you're calling a procedure in a loop (allocate frame, de-allocate frame, repeat), and the more state associated with the procedure the bigger the gain.

    ReplyDelete
  4. Thanks, Scott. That is a very concise and clear explanation. Maybe you should write a book! :-)

    But I do see you've been busily adding useful code to Github! Check it out folks: https://github.com/scott-swank/plsql-util

    ReplyDelete
    Replies
    1. Thank ya Steven.

      And actually I have a few updates to push up to github now that you mention it. In point of fact, once I get a couple things tidied up I'd like to talk to someone about providing a bit of my code (not yet on github) to Oracle. Who should I talk to on that front?

      Delete
    2. Scott, I am pretty use that Oracle will not accept code from outside contributors but why don't you follow up via email steven at feuerstein dot com, and we can explore further.

      Delete
    3. ARGH. I can't even type my sort of email address right. I meant to type: steven dot feuerstein at oracle dot com. But no worries. I got your email via my stevenfeuerstein domain. Thanks!

      Delete
  5. Hi Steven,

    As you have mentioned, The function call get replaced by the the code itself and that hasnt any associated context switches. So, if i have the below function with a huge code which gets replaced at the occurence of Function call, how is the procedural part of my code executed. A small description (any web link with detailed description) would be appreciated here.

    Function F return number is
    begin

    IF condition_1 THEN
    SELECT INTO value1
    ELSIF condition_2 THEN
    statements_2
    [ ELSIF condition_3 THEN
    statements_3
    ]...
    [ ELSE
    else_statements
    ]
    END IF;

    For rec in 1..10
    loop
    sum:=sum+rec;
    end loop;

    Return sum+value1;
    End if;


    Also, with reference to context switches, I always had a doubt of how does the inbuilt functions like nvl,decode, sum, avg etc. work ( i am aware of the standard package which sets the environment), but do we really call a PLSQL code in the background and are there any associated context switches.

    ReplyDelete
  6. re: how is the procedural part of my code executed

    I suggest that the best answer to this question is: don't worry about it. You don't need to know about or concern yourself with the internal operations of the compiler (which can change with each new release anyway). It does the right thing and ensures that the logical result of your code remains unchanged.

    re: context switches and inbuilt functions like nvl,decode, sum, avg

    These functions are implemented directly in the SQL engine. There is no context switch for the built-in SQL functions.

    ReplyDelete

Post a Comment

Popular posts from this blog

Quick Guide to User-Defined Types in Oracle PL/SQL

A Twitter follower recently asked for more information on user-defined types in the PL/SQL language, and I figured the best way to answer is to offer up this blog post. PL/SQL is a strongly-typed language . Before you can work with a variable or constant, it must be declared with a type (yes, PL/SQL also supports lots of implicit conversions from one type to another, but still, everything must be declared with a type). PL/SQL offers a wide array of pre-defined data types , both in the language natively (such as VARCHAR2, PLS_INTEGER, BOOLEAN, etc.) and in a variety of supplied packages (e.g., the NUMBER_TABLE collection type in the DBMS_SQL package). Data types in PL/SQL can be scalars, such as strings and numbers, or composite (consisting of one or more scalars), such as record types, collection types and object types. You can't really declare your own "user-defined" scalars, though you can define subtypes  from those scalars, which can be very helpful from the p

The differences between deterministic and result cache features

 EVERY once in a while, a developer gets in touch with a question like this: I am confused about the exact difference between deterministic and result_cache. Do they have different application use cases? I have used deterministic feature in many functions which retrieve data from some lookup tables. Is it essential to replace these 'deterministic' key words with 'result_cache'?  So I thought I'd write a post about the differences between these two features. But first, let's make sure we all understand what it means for a function to be  deterministic. From Wikipedia : In computer science, a deterministic algorithm is an algorithm which, given a particular input, will always produce the same output, with the underlying machine always passing through the same sequence of states.  Another way of putting this is that a deterministic subprogram (procedure or function) has no side-effects. If you pass a certain set of arguments for the parameters, you will always get

My two favorite APEX 5 features: Regional Display Selector and Cards

We (the over-sized development team for the PL/SQL Challenge - myself and my son, Eli) have been busy creating a new website on top of the PLCH platform (tables and packages): The Oracle Dev Gym! In a few short months (and just a part time involvement by yours truly), we have leveraged Oracle Application Express 5 to create what I think is an elegant, easy-to-use site that our users will absolutely love.  We plan to initially make the Dev Gym available only for current users of PL/SQL Challenge, so we can get feedback from our loyal user base. We will make the necessary adjustments and then offer it for general availability later this year. Anyway, more on that as the date approaches (the date being June 27, the APEX Open Mic Night at Kscope16 , where I will present it to a packed room of APEX experts). What I want to talk about today are two features of APEX that are making me so happy these days: Regional Display Selector and Cards. Regional Display Sel