Skip to content

Dynamic Calls to Optional Components

The purpose of this page is to describe how to access code in optional components. There are different alternatives but the recommended and most efficient way is to use Conditional Compilation. Dynamic PL/SQL through DBMS_SQL or running a dynamic statement using EXECUTE IMMEDIATE are possible alternatives to use but should be avoided.

What is Conditional Compilation

Conditional compilation is a way to make the PL/SQL code compile differently.

Below is an example of PL/SQL code with Conditional Compilation:

$IF boolean_static_expression $THEN  
   some pl/sql code  
$ELSE  
   other pl/sql code  
$END

Additional information regarding Conditional Compilation can be found in the Oracle documentation.

Benefits with Conditional Compilation

There are some cases where Conditional Compilation confers benefits over other solutions that require a different implementation approach. Some examples of these benefits are as follows:

  • Better performance (compared to Using Dynamic PL/SQL through DBMS_SQL)
    Compiled code always performs better than dynamic code.
  • Easier implementation (compared to a solution with stub packages, with or without any implementation)
    Just add a simple Conditional Compilation piece of code and you have finished your solution. Also there are no maintenance problems in the future.
  • Easier testing
    By amending a Boolean value in a package then you can test both of your cases very easily without the need to deploy/uninstall a component.

Drawback

  • Code needs to be recompiled when a Boolean constant is changed.
    This can cause some problems but in most cases the code recompiles itself when this is required. In a production environment at a customers site you should only change the Boolean package constants when running an installation or an upgrade.

How to format Conditional Compilation

In IFS Cloud the keywords $IF and $END should start at the beginning of the line and the rest of the PL/SQL code can be used as intended without taking any notice of the Conditional Compilation code.

WHILE (Client_SYS.Get_Next_From_Attr(attr_, ptr_, name_, value_)) LOOP  
   IF (name_ = 'ITEM_ID') THEN  
      newrec_.item_id := value_;  
      Todo_Item_API.Exist(newrec_.item_id);  
   ELSIF (name_ = 'PERSON_ID') THEN  
      newrec_.person_id := value_;  
$IF Component_Enterp_SYS.INSTALLED $THEN   
      Person_Info_API.Exist(newrec_.person_id);  
$ELSE  
      NULL;  
$END  
   ELSE  
      Error_SYS.Item_Not_Exist(lu_name_, name_, value_);  
   END IF;  
END LOOP;

Dynamic dependency between components

When IFS Cloud are installed, the framework creates packages called Component_<component name>_SYS (e.g. Component_Enterp_SYS) for all components that are installed in your installation. Besides packages for the installed components, packages for those components that are defined to be dynamically used from the installed components are created as well. These packages hold  information if the component, that the package refers to, is installed in the database or not. In the beginning of an installation, all component constants are set to FALSE (with the exception being, all already installed components that are not part of the delivery). At the end of the installation, constants are switched to TRUE for the components that have been installed, the others remain as FALSE. While switching these constants the status of the database objects will be affected. All invalid database objects are recompiled afterwards.

Please be aware that it is possible for a component to have a conditional compilation set to itself. This can be useful if an object used in a package is created as a Post Installation Object. Normally it is views, that are defined differently depending on which other components are installed, that are created as Post Installation Objects.

Information about which components that are installed or not, is stored in Module entity. The dynamic connections are fetched from the deploy.ini files and stored in ModuleDependency entity. This means that all usages of the Conditional Compilation component packages in the code must be reflected as a DYNAMIC connection in the deploy.ini. This is also the case when a component refers to itself.

Below is an example from deploy.ini

[Connections]  
APPSRV=DYNAMIC  
ENTERP=DYNAMIC  
DOCMAN=DYNAMIC  

Below is an example of generated code in Install.tem

-- The CompRegAndDep.sql is generated automatically in the build process  
START CompRegAndDep.sql  
EXEC Installation_SYS.Create_Component_Package(FALSE);  
...  
[installing components]  
...  
EXEC Installation_SYS.Create_Component_Package(TRUE);  
EXEC Database_SYS.Compile_All_Invalid_Objects;  
...

Below is an example of a generated Component_<component name>_SYS

CREATE OR REPLACE PACKAGE Component_Enterp_SYS IS  

module_ CONSTANT VARCHAR2(25) := 'FNDBAS';  
lu_name_ CONSTANT VARCHAR2(25) := 'ComponentEnterp';  
lu_type_ CONSTANT VARCHAR2(14) := 'System Service';  

-------------------------------------------------------------------------  
-------------------- LU SPECIFIC GLOBAL VARIABLES -----------------------  
-------------------------------------------------------------------------  

-------------------------------------------------------------------------  
-------------------- INSTALLED COMPONENTS -------------------------------  
-------------------------------------------------------------------------  

INSTALLED CONSTANT BOOLEAN := TRUE;  

END Component_Enterp_SYS;  

The packages Component_<component name>_SYS and their global constants can/should be used to enter specific code to be executed if a component is installed or not. Dependent on whether the component constant is TRUE or FALSE then different code is compiled and users can expect to get more efficient code compiled into the database. An example of such coding could be:

$IF Component_Enterp_SYS.INSTALLED $THEN  
      Person_Info_API.Exist(newrec_.person_id);  
$ELSE  
      NULL;  
$END

This gives us the opportunity to dispose of a lot of old dynamic PL/SQL code that executes at a considerably slower rate than compiled code.

If the Component_<component name>_SYS is missing in an development environment, there is a shortcut to temporary add it until the next build is executed. First you must insert the dependency, then call the procedure that generates the package.

INSERT INTO module_dependency_tab  
(module, dependent_module, dependency, rowversion)  
VALUES  
('<my component>', '<dynamic component>', 'DYNAMIC', SYSDATE);  

COMMIT;  

BEGIN  
   Installation_SYS.Create_Component_Package(TRUE);  
END;  
/

Conditional Compilation in Views

It is not possible to use Conditional Compilation when creating views in Oracle, but sometimes dynamically built views are needed while developing IFS Applications.  The framework has therefore added support for having Conditional Compilation in views.

When views with a conditional compilation are generated from.views files into deployable code, it is done in both.apv files and the method Post_Installation_View in the.apy file. In the apv, The.apv is deployed with Conditional Compilation, meaning only parts of the view that are available at deployment time will be included in the dynamic statement. The Post_Installation_View methods are executed after all components are deployed in the database, meaning that the parts of the view that are available in the database will be included. This means that the view must have the exact same interface no matter of the dynamic statements are true or false.

Developer Studio usages of Conditional Compilation

If you want an entire PL/SQL method to be excluded or included depending on another component, use the @DynamicComponentDependency annotation. It is strongly recommended to only use this annotation for implementation methods. Having it in methods published in the package specification might lead to deployment errors, and it will slow down the build time a lot. You may also use a static Boolean expression of your own to get the same result, by using the @DynamicDependency annotation.

Other areas where Conditional Compilation can be useful

In addition to checking whether a component is installed or not, there are many other places where Conditional compilation can be very useful. Below you can see some of these examples:

  • Tracing
    You can add trace texts that are only visible if you set a flag in a specific package. Alternatively you can insert specific data into tables so you can see what happened during the execution of your code. This avoids performance impacts on the code within a production environment.
  • Oracle Versions
    You can add code that behaves differently depending on which version of Oracle you are running. The package Dbms_Db_Versionholds information about which version you are running on.
  • Oracle Features
    If you have a specific Oracle feature installed you could compile the code so it becomes optional as to whether this feature is used or not.