SQLMentor // learn pl/sql

Conditional Compilation

Conditional compilation lets the PL/SQL compiler include or exclude parts of your source before it compiles — controlled by directives that start with $. The excluded code never becomes part of the compiled unit, so there is zero runtime cost. It is Oracle's mechanism for version-specific code, toggle-able debug instrumentation, and feature flags.

Selection Directives: $IF … $THEN … $END

The core construct chooses which code to compile based on a static (compile-time) boolean expression:

CREATE OR REPLACE PROCEDURE do_work IS
BEGIN
    $IF $$debug_on $THEN
        DBMS_OUTPUT.PUT_LINE('DEBUG: entering do_work at ' || SYSTIMESTAMP);
    $END

    -- ... real work ...
    NULL;
END do_work;
/

A selection directive can also have $ELSIF and $ELSE branches. The condition must be a static expression — literals, PLS_INTEGER/BOOLEAN compile-time constants, and inquiry directives only. It cannot reference variables, columns, or functions evaluated at runtime.

Inquiry Directives ($$name)

Inquiry directives, written $$name, supply compile-time values. Some are predefined; others you define yourself through the PLSQL_CCFLAGS parameter.

-- Define custom flags for this session (name:value pairs)
ALTER SESSION SET PLSQL_CCFLAGS = 'debug_on:TRUE, trace_level:2';

CREATE OR REPLACE PROCEDURE process_order(p_id IN NUMBER) IS
BEGIN
    $IF $$trace_level >= 2 $THEN
        DBMS_OUTPUT.PUT_LINE('TRACE: process_order(' || p_id || ')');
    $END
    NULL;
END process_order;
/

Predefined Inquiry Directives

Directive Compile-time value
$$PLSQL_LINE The current source line number (a PLS_INTEGER)
$$PLSQL_UNIT The name of the current unit (empty string for an anonymous block)
$$PLSQL_UNIT_OWNER The owner of the current unit (12c+)
$$PLSQL_UNIT_TYPE The unit type, e.g. PROCEDURE, PACKAGE BODY (12c+)
BEGIN
    DBMS_OUTPUT.PUT_LINE('Compiled from unit ' || $$PLSQL_UNIT ||
                         ', line ' || $$PLSQL_LINE);
END;
/

Version-Specific Code with DBMS_DB_VERSION

The built-in DBMS_DB_VERSION package exposes the database version as compile-time constants, so one source file can compile optimally on different Oracle releases:

CREATE OR REPLACE FUNCTION fast_concat(p_list IN SYS.ODCIVARCHAR2LIST)
RETURN VARCHAR2 IS
    v_result VARCHAR2(32767);
BEGIN
    $IF DBMS_DB_VERSION.VER_LE_11 $THEN
        -- Older releases: manual loop
        FOR i IN 1 .. p_list.COUNT LOOP
            v_result := v_result || p_list(i);
        END LOOP;
    $ELSE
        -- 12c+: use the newer, faster built-in path
        v_result := SYS.LISTAGG_helper(p_list);   -- illustrative
    $END
    RETURN v_result;
END fast_concat;
/

DBMS_DB_VERSION provides VERSION and RELEASE integers plus a family of boolean constants (VER_LE_11, VER_LE_12, VER_LE_18, VER_LE_19, VER_LE_21, …) that are TRUE/FALSE at compile time.

The $ERROR Directive

$ERROR … $END forces a compile-time error with a custom message — useful to reject an unsupported configuration or platform:

$IF DBMS_DB_VERSION.VER_LE_10 $THEN
    $ERROR 'This package requires Oracle 11g or later.' $END
$END

Seeing the Post-Processed Source

Because directives change what actually compiles, use DBMS_PREPROCESSOR to view the source after the directives are resolved — invaluable for debugging:

BEGIN
    DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE(
        object_type => 'PROCEDURE',
        schema_name => USER,
        object_name => 'PROCESS_ORDER'
    );
END;
/
The classic use case is debug instrumentation you can compile away completely for production. Ship the code with PLSQL_CCFLAGS = 'debug_on:FALSE' and the debug lines vanish from the compiled unit — no IF checks, no overhead — then recompile with debug_on:TRUE to bring them back while diagnosing an issue.
Changing PLSQL_CCFLAGS does not retroactively affect already-compiled units. You must recompile (ALTER … COMPILE) for new flag values to take effect. The flags a unit was compiled with are recorded in USER_PLSQL_OBJECT_SETTINGS.

Summary

  • Conditional compilation selects code at compile time with $IF / $ELSIF / $ELSE / $END — excluded code has zero runtime cost.
  • Conditions must be static expressions (literals, compile-time constants, inquiry directives).
  • Inquiry directives $$name come from PLSQL_CCFLAGS (custom) or are predefined ($$PLSQL_LINE, $$PLSQL_UNIT, …).
  • DBMS_DB_VERSION constants enable one source file to compile version-specific code paths.
  • $ERROR … $END raises a deliberate compile-time error.
  • DBMS_PREPROCESSOR.PRINT_POST_PROCESSED_SOURCE shows the source after directives are applied.
  • Recompile a unit for changed PLSQL_CCFLAGS to take effect; settings are recorded in USER_PLSQL_OBJECT_SETTINGS.