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. 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 packageDbms_Db_Version
holds 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.