Quantcast
Channel: Steve Hilker's Groups Activities
Viewing all articles
Browse latest Browse all 318

Rules Engine

$
0
0

If you ever wish to have a custom rules engine in plsql, here is one simple version of it.

- Rules are configured as simple SQL queries. These queries may use

- Bundle the rules and call it Rule Set and give an ID to it

- The caller will execute the rules engine proc by passing rule-set id as in parameter

- The rules engine proc will excute the rule queries one by one and record the result in the rule_output table

- The caller then can query the rule_output table to get the results and further understand the meaning of the result

I have used it in multiple projects

- to fire sequence of queries to introspect a domain object and signal other processes
- to generate reporting data
- to enrich a domin object

- To implement purge requirements (Ruleset triggered to Quartz scheduler)
Thought it might of some help to others.

Features

-User configures list of SQL select queries - Called rule queries.

- Rule Queries are bundled under the name RulesSet

- Caller provides the RuleSet name as input and execute the rules engine - to fire all the rules configured under the ruleset

- The rules engine prepares / parses the rule queries

Rules queries may use bind variables

- User configures bind-queries against each bind-variable, in the bind-query tables.

- Engine will execute the bind SQL queries, get the value and replace it to the Rule query to prepare the SQL Query

- Parsed SQL Queries are executed by the engine and results are collected in a rule-output tables

Controlling the execution of the rules under a RuleSet

- While the engine always executes the list of the Rules for a given RuleSet, user may wish to abort after a certain condition is met.

- In other words, the engine executes the list of Rule Queries for a given RuleSet one by one say in a while loop.

- The caller is provided with an option to control the while-loop's condition.

- The while loop's condition can be configured as another Rule-Query - breakConditionQuery rule

Passing values to the rules-engine

- A oracle global session table is used to pass values to the rule engine procedure

- Caller will insert the input parameters as key value pairs in input_param session table and then invoke the rules-engine proc in the same session

- Bind variable queries & Rule queries will use these values.

Dependency:

- Uses a database logger component similar to apache log4j, it is included as well.

CODE

/****
DDLs
****/

CREATE TABLE MY_log_properties
(
   logger      VARCHAR2 (200) PRIMARY KEY,
   loglevel    VARCHAR2 (100),
   createdby   VARCHAR2 (100),
   createddt   DATE,
   updateddt   DATE,
   updatedby   VARCHAR2 (100)
);


CREATE TABLE MY_log
(
   logid           NUMBER,
   code            VARCHAR2 (100),
   msg             CLOB,
   logger          VARCHAR2 (200),
   loglevel        VARCHAR2 (10),
   iden1           VARCHAR2 (100),
   iden2           VARCHAR2 (100),
   iden3           VARCHAR2 (100),
   iden4           VARCHAR2 (100),
   iden5           VARCHAR2 (100),
   createdby       VARCHAR2 (100),
   sys_timestamp   TIMESTAMP
);


CREATE INDEX MY_log_logid_idx
   ON MY_log (logid);

CREATE INDEX MY_log_time_idx
   ON MY_log (sys_timestamp);

CREATE INDEX MY_log_iden_idx
   ON MY_log (iden1,
                iden2,
                iden3,
                iden4,
                iden5);

CREATE SEQUENCE MY_log_seq
   MINVALUE 1
   MAXVALUE 999999999999999
   CYCLE;

--------------------------

CREATE TABLE MY_RULE
(
   ID           NUMBER NOT NULL,
   APPID        VARCHAR2 (300 BYTE) NOT NULL,
   RULE_ID      VARCHAR2 (100 BYTE),
   RULESET_ID   VARCHAR2 (100 BYTE) NOT NULL,
   RULE_QUERY   CLOB NOT NULL,
   UPDDT        TIMESTAMP (6) DEFAULT SYSTIMESTAMP
);


ALTER TABLE MY_RULE ADD (
  PRIMARY KEY
  (RULE_ID));


CREATE TABLE MY_RULE_BINDVARIABLES
(
   APPID               VARCHAR2 (300 BYTE) NOT NULL,
   VARIABLENAME        VARCHAR2 (64 BYTE),
   BIND_QUERY          CLOB,
   INC_TYPE            VARCHAR2 (2 BYTE) DEFAULT 'EQ' NOT NULL,
   CACHE_WITHIN_EXEC   VARCHAR2 (1 BYTE) DEFAULT 'Y' NOT NULL,
   UPDDT               TIMESTAMP (6) DEFAULT SYSTIMESTAMP
);


ALTER TABLE MY_RULE_BINDVARIABLES ADD (
  PRIMARY KEY
  (VARIABLENAME));

CREATE TABLE MY_RULE_EXE_CONFIG
(
   ID                    NUMBER,
   APPID                 VARCHAR2 (300 BYTE) NOT NULL,
   RULESET_ID            VARCHAR2 (100 BYTE) NOT NULL,
   BREAK_CONDN_BEF_AFT   VARCHAR2 (3 BYTE) DEFAULT 'BEF',
   BREAKING_RULEID       VARCHAR2 (100 BYTE) NOT NULL,
   UPDDT                 TIMESTAMP (6) DEFAULT SYSTIMESTAMP
);

ALTER TABLE MY_RULE_EXE_CONFIG ADD (
  PRIMARY KEY
  (ID));

CREATE GLOBAL TEMPORARY TABLE MY_RE_INPUT_PARAM
(
   EXEID   VARCHAR2 (500),
   KEY     VARCHAR2 (500),
   VALUE   VARCHAR2 (500)
)
ON COMMIT DELETE ROWS;

CREATE TABLE MY_RULE_OUTPUT
(
   APPID        VARCHAR2 (300 BYTE) NOT NULL,
   OUTPUTID     VARCHAR2 (300 BYTE),
   RULE_ID      VARCHAR2 (100 BYTE),
   RULESET_ID   VARCHAR2 (100 BYTE),
   EXEID        VARCHAR2 (200 BYTE),
   RECID        NUMBER (19),
   COLIDX       NUMBER (10),
   COLNAME      VARCHAR2 (100 BYTE),
   COLTYPE      VARCHAR2 (4000 BYTE),
   COLVAL       VARCHAR2 (4000 BYTE),
   COLVAL_DT    DATE,
   COLVAL_TS    TIMESTAMP (6),
   COLVAL_CL    CLOB,
   UPDDT        TIMESTAMP (6) DEFAULT SYSTIMESTAMP
);


CREATE INDEX MY_RULE_OUTPUT_IDX1
   ON MY_RULE_OUTPUT (APPID, RULESET_ID, EXEID);

CREATE INDEX MY_RULE_OUTPUT_IDX2
   ON MY_RULE_OUTPUT (APPID, RULE_ID, EXEID);

CREATE UNIQUE INDEX MY_RULE_OUTPUT_PK
   ON MY_RULE_OUTPUT (OUTPUTID, COLIDX);


ALTER TABLE MY_RULE_OUTPUT ADD (
  CONSTRAINT MY_RULE_OUTPUT_PK
  PRIMARY KEY
  (OUTPUTID, COLIDX)
  USING INDEX MY_RULE_OUTPUT_PK
  ENABLE VALIDATE);


CREATE SEQUENCE MY_RULE_OUTPUT_SEQ
   START WITH 81
   MAXVALUE 99999999999999
   MINVALUE 1
   CYCLE
   CACHE 20
   NOORDER;


CREATE OR REPLACE TYPE RowData IS TABLE OF VARCHAR2 (4000);

CREATE OR REPLACE TYPE ResultSet IS TABLE OF RowData;

-----------------------------------------------------


CREATE OR REPLACE PACKAGE MY_logger
AS
   PROCEDURE LOG (pLogger      MY_log.logger%TYPE,
                  pLogLevel    MY_log.loglevel%TYPE,
                  pCode        MY_log.code%TYPE,
                  pMsg         MY_log.msg%TYPE,
                  pIden1       MY_log.iden1%TYPE DEFAULT NULL,
                  pIden2       MY_log.iden2%TYPE DEFAULT NULL,
                  pIden3       MY_log.iden3%TYPE DEFAULT NULL,
                  pIden4       MY_log.iden4%TYPE DEFAULT NULL,
                  pIden5       MY_log.iden5%TYPE DEFAULT NULL);

   gv_logging_status   VARCHAR2 (100);
END MY_logger;
/

/********************************************************************************************
* INPUT         : pLogger     --type of logger
*                 pLogLevel   -- log level,
*                 pCode       -- error code Passed,
*                 pMsg        -- Error Message Passed
*                 pIden1      --Identifier 1
*                 pIden2      --Identifier 2
*                 pIden3      --Identifier 3
*                 pIden4      --Identifier 4
*                 pIden5      --Identifier 5
----------------------------------------------------
* Description   :IF logging status ("*" in MY_LOG_PROPERTIES table is OFF then return )
*                  
*                 Based On Logging level set in MY_log_properties , logging will be saved
*                 If the Passed Level is less than the level of DB , then logs will not be
*                 Stored. (If logging status not matched or passed null thenby default
*                          logs will be saved)                           
**********************************************************************************************/

CREATE OR REPLACE PACKAGE BODY MY_logger
AS
   PROCEDURE LOG (pLogger      MY_log.logger%TYPE,
                  pLogLevel    MY_log.loglevel%TYPE,
                  pCode        MY_log.code%TYPE,
                  pMsg         MY_log.msg%TYPE,
                  pIden1       MY_log.iden1%TYPE DEFAULT NULL,
                  pIden2       MY_log.iden2%TYPE DEFAULT NULL,
                  pIden3       MY_log.iden3%TYPE DEFAULT NULL,
                  pIden4       MY_log.iden4%TYPE DEFAULT NULL,
                  pIden5       MY_log.iden5%TYPE DEFAULT NULL)
   AS
      PRAGMA AUTONOMOUS_TRANSACTION;
      lnpLogLevel       NUMBER := 0;
      lnDBLogLevel      NUMBER := 0;
      generated_logid   MY_log.logid%TYPE;
      lDBLogLevel       MY_log.loglevel%TYPE := 'ERR';
      npLogLevel        NUMBER := 0;
      nDBLogLevel       NUMBER := 0;
   BEGIN
      BEGIN
         SELECT UPPER (LOGLEVEL)
           INTO gv_logging_status
           FROM MY_log_properties
          WHERE logger = '*' AND ROWNUM < 2;

         -- Returning the call from procedure , logging status is OFF
         IF gv_logging_status = 'OFF'
         THEN
            RETURN;
         END IF;
      EXCEPTION
         WHEN OTHERS
         THEN
            gv_logging_status := 'OFF';
      END;

      -- Checking the DB Log Level for the input logger
      BEGIN
         SELECT LOGLEVEL
           INTO lDBLogLevel
           FROM MY_log_properties
          WHERE UPPER (pLogger) = UPPER (logger) AND ROWNUM < 2;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            BEGIN
               -- IF exact match is not found then checking for the wild card search based on the maximum defined log level
               SELECT loglevel
                 INTO lDBLogLevel
                 FROM (  SELECT DISTINCT LOGLEVEL, LENGTH (logger), ROWNUM rn
                           FROM MY_log_properties
                          WHERE UPPER (pLogger) LIKE (UPPER (logger) || '%')
                       ORDER BY LENGTH (logger) DESC)
                WHERE rn = 1;
            EXCEPTION
               WHEN NO_DATA_FOUND
               THEN
                  lDBLogLevel := 'ERR';
               WHEN OTHERS
               THEN
                  -- when any error in Query , raise the error back to environment
                  RAISE;
            END;
      END;


      -- Making the Level for passed logger
      SELECT DECODE (pLogLevel,
                     'ON', 2,
                     'ERR', 2,
                     'WAR', 1,
                     'DEB', 0,
                     -1)
        INTO lnpLogLevel
        FROM DUAL;

      -- Fetching the DB Level for passed logger
      SELECT DECODE (lDBLogLevel,  'ERR', 2,  'WAR', 1,  'DEB', 0,  2, -1)
        INTO lnDBLogLevel
        FROM DUAL;

      IF gv_logging_status = 'ON' AND (lnpLogLevel = -1 OR lnDBLogLevel = -1)
      THEN
         -- Overriding the LOG logic , if logging status is ON and logging indicators are not passed then
         -- based on this flag logging will be done
         lnpLogLevel := 2;
         lnDBLogLevel := 2;
      END IF;

      IF lnDBLogLevel <= lnpLogLevel
      THEN
         -- creating the ID for LOGS
         SELECT LPAD (MY_log_seq.NEXTVAL, 5, 0)
           INTO generated_logid
           FROM DUAL;

         -- If all validations passes then we have to insert into the log table
         INSERT INTO PMTS_PSH_OWNER.MY_LOG (logger,
                                              loglevel,
                                              logid,
                                              code,
                                              msg,
                                              iden1,
                                              iden2,
                                              iden3,
                                              iden4,
                                              iden5,
                                              sys_timestamp)
              VALUES (pLogger,
                      ploglevel,
                      generated_logid,
                      pCode,
                      pMsg,
                      pIden1,
                      pIden2,
                      pIden3,
                      pIden4,
                      pIden5,
                      CURRENT_TIMESTAMP);
      END IF;



      COMMIT;
   END LOG;
END MY_logger;
/

------------------------------------------------------------------------------

create or replace
PACKAGE "MY_RULESENGINE"
AS
   TYPE BindQueryCacheType IS TABLE OF CLOB
      INDEX BY VARCHAR2 (100);

   aLOGID   MY_LOG.logid%TYPE;

   PROCEDURE pub_fireRules (pAppId        MY_RULE.APPID%TYPE,
                            pRuleSetId    MY_RULE.RULESET_ID%TYPE,
                            pExecId       MY_RULE_OUTPUT.EXEID%TYPE);

   FUNCTION parseQuery (pAppId     MY_RULE.APPID%TYPE,
                        pQuery     CLOB,
                        pExecId    MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN CLOB;

   FUNCTION exeRuleBindQuery (pAppId           MY_RULE.APPID%TYPE,
                              pVariableName    VARCHAR2,
                              pExecId          MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN CLOB;

   FUNCTION exeAnyQuery (pQuery CLOB)
      RETURN ResultSet
      PIPELINED;

   FUNCTION getRuleBindQueryResult (pQuery CLOB, incType VARCHAR2)
      RETURN CLOB;

   PROCEDURE getColumnDesc (pQuery                   CLOB,
                            oColCnt    IN OUT        NUMBER,
                            oDescQry   IN OUT NOCOPY DBMS_SQL.DESC_TAB);

   PROCEDURE exeRuleQryAndGenOutput (
      pAppId           MY_RULE.APPID%TYPE,
      exeId            MY_RULE_OUTPUT.EXEID%TYPE,
      ruleId           MY_RULE_OUTPUT.RULE_ID%TYPE,
      ruleSetId        MY_RULE_OUTPUT.RULESET_ID%TYPE,
      parsedRuleQry    CLOB);

   FUNCTION shouldBreak (pAppId     MY_RULE.APPID%TYPE,
                         pQuery     CLOB,
                         pExecId    MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN BOOLEAN;

   FUNCTION isSelectQuery (pParsedQuery CLOB)
      RETURN BOOLEAN;

   PROCEDURE exeAnyNonSelectQuery (
      pAppId           MY_RULE.APPID%TYPE,
      exeId            MY_RULE_OUTPUT.EXEID%TYPE,
      ruleId           MY_RULE_OUTPUT.RULE_ID%TYPE,
      ruleSetId        MY_RULE_OUTPUT.RULESET_ID%TYPE,
      parsedRuleQry    CLOB);
END MY_RULESENGINE;

/**
BODY
****/


create or replace
PACKAGE BODY                MY_RULESENGINE
AS
   aBindQryCache   BindQueryCacheType;

   /***************************************************************************
   * TYPE      : PROCEDURE
   * PURPOSE   : Gateway Proc to Fire Rules
   * INPUT     : pAppId      <ApplicationID>
   *           : pRuleSetId  <RuleID>
   *           : pExecId
   * PROCESS   : This Proc Will be called directly from the mapper to fire the
   *             Rules , process is as below
   *              1: Check Breaking Condition for APPLICATION and RULE SETID
   *              2: Fetch The Breaking Query from rule table
   *              3: Check the Breaking Condition AFTER or BEFORE
   *****************************************************************************/
   PROCEDURE pub_fireRules (pAppId        MY_RULE.APPID%TYPE,
                            pRuleSetId    MY_RULE.RULESET_ID%TYPE,
                            pExecId       MY_RULE_OUTPUT.EXEID%TYPE)
   AS
      CURSOR rules_sql
      IS
           SELECT rule_query, rule_id, ruleset_id
             FROM MY_RULE
            WHERE     appid = pAppId
                  AND ruleset_id = pRulesetId
                  AND rule_id NOT IN
                         (SELECT BREAKING_RULEID
                            FROM MY_RULE_EXE_CONFIG
                           WHERE appid = pAppId AND ruleset_id = pRulesetId)
         ORDER BY id;

      currParsedRuleQry   CLOB := NULL;
      breakConditionQry   CLOB := NULL;
      whenToBreak         MY_RULE_EXE_CONFIG.BREAK_CONDN_BEF_AFT%TYPE;
      chkBreakCondition   VARCHAR (1) := 'N';
   BEGIN
      SELECT MY_LOG_SEQ.NEXTVAL INTO aLOGID FROM DUAL;

      MY_LOGGER.LOG ('MY_RULESENGINE.pub_fireRules',
                       'DEB',
                       '0',
                       'ENTER pub_fireRules',
                       pExecId,
                       pRuleSetId,
                       NULL);

      FOR i IN (SELECT BREAK_CONDN_BEF_AFT, BREAKING_RULEID
                  FROM MY_RULE_EXE_CONFIG
                 WHERE appid = pAppId AND ruleset_id = pRulesetId)
      LOOP
         -- Bypassing the BreakingRule Condition  if conditionid =0
         IF (i.BREAK_CONDN_BEF_AFT IS NOT NULL AND i.BREAKING_RULEID <> 0)
         THEN
            SELECT rule_query
              INTO breakConditionQry
              FROM MY_RULE
             WHERE     appid = pAppId
                   AND ruleset_id = pRulesetId
                   AND rule_id = i.BREAKING_RULEID;

            chkBreakCondition := 'Y';
         END IF;

         whenToBreak := i.BREAK_CONDN_BEF_AFT;
         MY_LOGGER.LOG (
            'MY_RULESENGINE.pub_fireRules',
            'DEB',
            '0',
               'BreakingCondition:'
            || chkBreakCondition
            || '-'
            || whenToBreak
            || '-',
            pExecId,
            pRuleSetId,
            NULL,
            aLOGID,
            'Normal');
      END LOOP;

      aBindQryCache.delete;

      FOR ruleQueries IN rules_sql
      LOOP
         IF ( (chkBreakCondition = 'Y') AND (whenToBreak = 'BEF'))
         THEN
            IF shouldBreak (pAppId,
                            parseQuery (pAppId, breakConditionQry, pExecId),
                            pExecId)
            THEN
               aBindQryCache.delete;
               MY_LOGGER.LOG ('MY_RULESENGINE.pub_fireRules',
                                'DEB',
                                '0',
                                'EXIT pub_fireRules (breaking-BEF)',
                                pExecId,
                                pRuleSetId,
                                ruleQueries.rule_id,
                                aLOGID,
                                'Normal');
               EXIT;
            END IF;
         END IF;

         currParsedRuleQry :=
            parseQuery (pAppId, ruleQueries.rule_query, pExecId);
         MY_LOGGER.LOG ('MY_RULESENGINE.pub_fireRules',
                          'DEB',
                          '0',
                          'CurrentParsedRuleQuery:' || currParsedRuleQry,
                          pExecId,
                          pRuleSetId,
                          ruleQueries.rule_id,
                          aLOGID,
                          'Normal');

         IF (isSelectQuery (currParsedRuleQry))
         THEN
            exeRuleQryAndGenOutput (pAppId,
                                    pExecId,
                                    ruleQueries.rule_id,
                                    pRuleSetId,
                                    currParsedRuleQry);
         ELSE
            exeAnyNonSelectQuery (pAppId,
                                  pExecId,
                                  ruleQueries.rule_id,
                                  pRuleSetId,
                                  currParsedRuleQry);
         END IF;

         MY_LOGGER.LOG (
            'MY_RULESENGINE.pub_fireRules',
            'DEB',
            '0',
            'exeRuleQryAndGenOutput - Completed for ' || ruleQueries.rule_id,
            pExecId,
            pRuleSetId,
            ruleQueries.rule_id,
            aLOGID,
            'Normal');

         IF ( (chkBreakCondition = 'Y') AND (whenToBreak = 'AFT'))
         THEN
            IF shouldBreak (pAppId,
                            parseQuery (pAppId, breakConditionQry, pExecId),
                            pExecId)
            THEN
               MY_LOGGER.LOG ('MY_RULESENGINE.pub_fireRules',
                                'DEB',
                                '0',
                                'EXIT pub_fireRules (breaking-AFT)',
                                pExecId,
                                pRuleSetId,
                                ruleQueries.rule_id,
                                aLOGID,
                                'Normal');
               EXIT;
            END IF;
         END IF;
      END LOOP;

      aBindQryCache.delete;
      MY_LOGGER.LOG ('MY_RULESENGINE.pub_fireRules',
                       'DEB',
                       '0',
                       'EXIT pub_fireRules',
                       pExecId,
                       pRuleSetId,
                       NULL,
                       aLOGID,
                       'Normal');
   END pub_fireRules;

   /***************************************************************************
   * TYPE      : FUNCTION
   * PURPOSE   : Create a Parsed Query
   * INPUT     : pAppId      <ApplicationID>
   *           : pQuery  <Query String>
   *           : pExecId
   * PROCESS   : This Proc Will be called to create the Query
   *              Setting of parameter will be done and query will be properly
   *              Formed <Query will be picked with a bind variable in it>
   *****************************************************************************/
   FUNCTION parseQuery (pAppId     MY_RULE.APPID%TYPE,
                        pQuery     CLOB,
                        pExecId    MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN CLOB
   AS
      parsedQuery     CLOB := pQuery;
      vPattern        VARCHAR2 (10) := '\$[^\$]+\$';
      vVariableName   VARCHAR2 (65) := NULL;
      i               NUMBER := 0;
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :parseQuery');
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:pAppId=' || pAppId);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 2:pQuery=' || pQuery);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 3:pExecId=' || pExecId);
      -- Parse all the variables in the rule query
      vVariableName :=
         REGEXP_SUBSTR (parsedQuery,
                        vPattern,
                        1,
                        1,
                        'm');

      WHILE ( (LENGTH (vVariableName) > 0) AND (vVariableName IS NOT NULL))
      LOOP
         IF (vVariableName IS NOT NULL)
         THEN
            IF (vVariableName = '$p.pExecId$')
            THEN
               parsedQuery :=
                  REGEXP_REPLACE (parsedQuery,
                                  vPattern,
                                  pExecId,
                                  1,
                                  1,
                                  'm');
            ELSIF (vVariableName LIKE '$v.%')
            THEN
               parsedQuery :=
                  REGEXP_REPLACE (
                     parsedQuery,
                     vPattern,
                     exeRuleBindQuery (pAppId, vVariableName, pExecId),
                     1,
                     1,
                     'm');
            ELSIF (vVariableName LIKE '$p.%')
            THEN
               MY_LOGGER.LOG (
                  'MY_RULESENGINE.parseQuery',
                  'ERR',
                  '-20501',
                     'RE-Variable Name '
                  || vVariableName
                  || ' is not supported in the query('
                  || pQuery
                  || ') ExecId('
                  || pExecId
                  || ')',
                  pExecId,
                  aLOGID,
                  NULL,
                  NULL,
                  'Error');
               raise_application_error (
                  -20501,
                     'RE-Variable Name '
                  || vVariableName
                  || ' is not supported in the query('
                  || pQuery
                  || ') ExecId('
                  || pExecId
                  || ')',
                  TRUE);
            ELSE
               MY_LOGGER.LOG (
                  'MY_RULESENGINE.parseQuery',
                  'ERR',
                  '-20500',
                     'RE-Variable Name '
                  || vVariableName
                  || ' is not supported in the query('
                  || pQuery
                  || ') ExecId('
                  || pExecId
                  || ')',
                  pExecId,
                  aLOGID,
                  NULL,
                  NULL,
                  'Error');
               raise_application_error (
                  -20500,
                     'RE-Variable Name '
                  || vVariableName
                  || ' is not supported in the query('
                  || pQuery
                  || ') ExecId('
                  || pExecId
                  || ')',
                  TRUE);
            END IF;
         END IF;

         vVariableName :=
            REGEXP_SUBSTR (parsedQuery,
                           vPattern,
                           1,
                           1,
                           'm');
      END LOOP;

      RETURN parsedQuery;
   END parseQuery;

   /**********************************************************************************************
   * TYPE      : FUNCTION
   *
   * PURPOSE   : Create a Query with Bind Variables
   *
   * INPUT     : pAppId      <ApplicationID>
   *           : pVariableName  <Variable Names>
   *           : pExecId
   *
   * PROCESS   : This Proc Will be called to create Bind Variable Query
   *             and return the output for that BIND variable to the calling
   *             Process <Bind Variable needs to be configured in MY_rule_bindvariables table>
   *
   **********************************************************************************************/
   FUNCTION exeRuleBindQuery (pAppId           MY_RULE.APPID%TYPE,
                              pVariableName    VARCHAR2,
                              pExecId          MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN CLOB
   AS
      vRuleBindQuery      CLOB := NULL;
      vPattern            VARCHAR2 (10) := '\$[^\$]+\$';
      localVariableName   VARCHAR2 (65) := NULL;
      incType             VARCHAR2 (2) := 'IN';
      cache               MY_RULE_BINDVARIABLES.CACHE_WITHIN_EXEC%TYPE;
      cResult             CLOB := NULL;
   BEGIN

      BEGIN
         -- Return the result if already cached
         IF aBindQryCache.EXISTS (pVariableName)
         THEN
            cResult := aBindQryCache (pVariableName);
            MY_LOGGER.LOG ('MY_RULESENGINE.exeRuleBindQuery',
                             'DEB',
                             '0',
                             'Result from CACHE:' || cResult,
                             pExecId,
                             NULL,
                             NULL,
                             aLOGID,
                             'Normal');
            RETURN cResult;
         END IF;

         SELECT BIND_QUERY, INC_TYPE, CACHE_WITHIN_EXEC
           INTO vRuleBindQuery, incType, cache
           FROM MY_RULE_BINDVARIABLES
          WHERE variablename = pVariableName AND appid = pAppId;

         localVariableName :=
            REGEXP_SUBSTR (vRuleBindQuery,
                           vPattern,
                           1,
                           1,
                           'm');

         MY_LOGGER.LOG (
            'MY_RULESENGINE.exeRuleBindQuery',
            'DEB',
            '0',
            'Unparsed SQL/Inc_type:' || vRuleBindQuery || '/' || incType,
            pExecId,
            NULL,
            NULL,
            aLOGID,
            'Normal');

         IF (    (LENGTH (localVariableName) > 0)
             AND (localVariableName IS NOT NULL))
         THEN
            vRuleBindQuery := parseQuery (pAppId, vRuleBindQuery, pExecId);

            MY_LOGGER.LOG (
               'MY_RULESENGINE.exeRuleBindQuery',
               'DEB',
               '0',
               'Parsed SQL/Inc_type:' || vRuleBindQuery || '/' || incType,
               pExecId,
               NULL,
               NULL,
               aLOGID,
               'Normal');
         END IF;

         cResult := getRuleBindQueryResult (vRuleBindQuery, incType);

         -- Add to cache
         IF (UPPER (cache) = 'Y')
         THEN
            aBindQryCache (pVariableName) := cResult;
         END IF;

         MY_LOGGER.LOG ('MY_RULESENGINE.exeRuleBindQuery',
                          'DEB',
                          '0',
                          'Result:' || cResult,
                          pExecId,
                          NULL,
                          NULL,
                          aLOGID,
                          'Normal');
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            MY_LOGGER.LOG (
               'MY_RULESENGINE.exeRuleBindQuery',
               'ERR',
               SQLCODE,
                  'RE- Rule Bind query for the Variable Name '
               || pVariableName
               || ' is not found for ExecId('
               || pExecId
               || ')',
               pExecId,
               '-20502',
               aLOGID,
               'Error');
            raise_application_error (
               -20502,
                  'RE- Rule Bind query for the Variable Name '
               || pVariableName
               || ' is not found for ExecId('
               || pExecId
               || ')',
               TRUE);
      END;

      RETURN cResult;
   END exeRuleBindQuery;


   /***************************************************************************
   * TYPE      : FUNCTION
   * PURPOSE   : Create a Query with Bind Variables
   * INPUT     : pAppId      <ApplicationID>
   *           : pVariableName  <Variable Names>
   *           : pExecId
   * PROCESS   : This Proc Will be called to create the Query
   *              Setting of parameter will be done and query will be properly
   *              Formed
   *****************************************************************************/
   FUNCTION getRuleBindQueryResult (pQuery CLOB, incType VARCHAR2)
      RETURN CLOB
   AS
      colCount       NUMBER := 0;
      ctxQryResult   CLOB := NULL;

      CURSOR c1
      IS
         SELECT * FROM TABLE (exeAnyQuery (pQuery));

      currRow        RowData;
      currRowStr     CLOB;
      recordFound    BOOLEAN := FALSE;
      desctab        DBMS_SQL.DESC_TAB;
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :getRuleBindQueryResult');
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:pQuery=' || pQuery);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 2:incType=' || incType);

      IF incType = 'IN'
      THEN
         OPEN c1;

         LOOP
            FETCH c1 INTO currRow;

            EXIT WHEN c1%NOTFOUND;
            colCount := currRow.COUNT;
            currRowStr := NULL;
            recordFound := TRUE;

            FOR i IN 1 .. currRow.COUNT
            LOOP
               currRowStr :=
                     currRowStr
                  || ''''
                  || REPLACE (currRow (i), '''', '''''')
                  || '''';

               IF (i < currRow.COUNT)
               THEN
                  currRowStr := currRowStr || ',';
               END IF;
            END LOOP;

            IF (colCount > 1)
            THEN
               currRowStr := '(' || currRowStr || ')';
            END IF;

            ctxQryResult := ctxQryResult || currRowStr || ',';
         END LOOP;

         CLOSE c1;

         -- Remove the extra ,
         ctxQryResult := SUBSTR (ctxQryResult, 0, LENGTH (ctxQryResult) - 1);

         IF (NOT recordFound)
         THEN
            getColumnDesc (pQuery, colCount, desctab);
            currRowStr := NULL;

            FOR i IN 1 .. colCount
            LOOP
               currRowStr := currRowStr || '''' || '''';

               IF (i < currRow.COUNT)
               THEN
                  currRowStr := currRowStr || ',';
               END IF;
            END LOOP;

            IF (colCount > 1)
            THEN
               currRowStr := '(' || currRowStr || ')';
            END IF;

            ctxQryResult := ctxQryResult || currRowStr || ',';
         END IF;
      ELSIF incType = 'EQ'
      THEN
         BEGIN
            SELECT * INTO currRow FROM TABLE (exeAnyQuery (pQuery));

            ctxQryResult :=
               '''' || REPLACE (currRow (1), '''', '''''') || '''';
         EXCEPTION
            WHEN NO_DATA_FOUND
            THEN
               ctxQryResult := '''''';
            WHEN OTHERS
            THEN
               MY_LOGGER.LOG ('MY_RULESENGINE.getRuleBindQueryResult',
                                'ERR',
                                SQLCODE,
                                SQLERRM,
                                '-',
                                aLOGID,
                                'Error');
               RAISE;
         END;
      END IF;

      RETURN ctxQryResult;
   EXCEPTION
      WHEN OTHERS
      THEN
         IF c1%ISOPEN
         THEN
            CLOSE c1;
         END IF;

         MY_LOGGER.LOG ('MY_RULESENGINE.getRuleBindQueryResult',
                          'ERR',
                          SQLCODE,
                          SQLERRM,
                          '-',
                          aLOGID,
                          'Error');
         RAISE;
   END getRuleBindQueryResult;

   /***************************************************************************
   * TYPE      : FUNCTION
   * PURPOSE   : upper level to execute the Query
   * INPUT     : pAppId      <ApplicationID>
   *           : pVariableName  <Variable Names>
   *           : pExecId
   * PROCESS   : This Proc Will be called to create the Query
   *              Setting of parameter will be done and query will be properly
   *              Formed
   *****************************************************************************/
   FUNCTION exeAnyQuery (pQuery CLOB)
      RETURN ResultSet
      PIPELINED
   AS
      currRow      RowData := NULL;
      v_cur_hdl    INT;
      ret          NUMBER;
      desctab      DBMS_SQL.DESC_TAB;
      colcnt       NUMBER;
      refDate      DATE;
      refNum       NUMBER;
      refVarchar   VARCHAR2 (4000);
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :exeAnyQuery');
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:pQuery=' || pQuery);
      v_cur_hdl := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.PARSE (v_cur_hdl, pQuery, DBMS_SQL.NATIVE);
      DBMS_SQL.DESCRIBE_COLUMNS (v_cur_hdl, colcnt, desctab);

      FOR i IN 1 .. colcnt
      LOOP
         IF desctab (i).col_type = DBMS_TYPES.NO_DATA
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl,
                                    i,
                                    refVarchar,
                                    4000);
         ELSIF desctab (i).col_type IN
                  (181,
                   DBMS_TYPES.TYPECODE_DATE,
                   DBMS_TYPES.TYPECODE_TIMESTAMP,
                   DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ,
                   DBMS_TYPES.TYPECODE_TIMESTAMP_TZ)
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refDate);
         ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_NUMBER
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refNum);
         ELSE
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl,
                                    i,
                                    refVarchar,
                                    4000);
         END IF;
      END LOOP;

      ret := DBMS_SQL.EXECUTE (v_cur_hdl);

      LOOP
         IF DBMS_SQL.FETCH_ROWS (v_cur_hdl) > 0
         THEN
            currRow := NEW RowData ();

            FOR i IN 1 .. colcnt
            LOOP
               IF desctab (i).col_type = DBMS_TYPES.NO_DATA
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refVarchar);
                  currRow.EXTEND;
                  currRow (i) := refVarchar;
               ELSIF desctab (i).col_type IN
                        (181,
                         DBMS_TYPES.TYPECODE_DATE,
                         DBMS_TYPES.TYPECODE_TIMESTAMP,
                         DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ,
                         DBMS_TYPES.TYPECODE_TIMESTAMP_TZ)
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refDate);
                  currRow.EXTEND;
                  currRow (i) :=
                     TO_CHAR (refDate, 'DD-MON-YYYY HH12.MI.SS AM');
               ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_NUMBER
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refNum);
                  currRow.EXTEND;
                  currRow (i) := TO_CHAR (refNum);
               ELSE
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refVarchar);
                  currRow.EXTEND;
                  currRow (i) := refVarchar;
               END IF;
            END LOOP;

            PIPE ROW (currRow);
         ELSE
            EXIT;
         END IF;
      END LOOP;

      DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
   EXCEPTION
      WHEN OTHERS
      THEN
         IF DBMS_SQL.IS_OPEN (v_cur_hdl)
         THEN
            DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
         END IF;

         MY_LOGGER.LOG ('MY_RULESENGINE.exeAnyQuery',
                          'ERR',
                          SQLCODE,
                          SQLERRM,
                          '-',
                          aLOGID,
                          'Error');
         RAISE;
   END exeAnyQuery;

   PROCEDURE getColumnDesc (pQuery                   CLOB,
                            oColCnt    IN OUT        NUMBER,
                            oDescQry   IN OUT NOCOPY DBMS_SQL.DESC_TAB)
   AS
      v_cur_hdl   INT;
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :getColumnDesc ');
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:pQuery=' || pQuery);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 2:oColCnt=' || oColCnt);
      ----DBMS_OUTPUT.PUT_LINE ('Parameter 3:oDescQry=' || oDescQry);
      v_cur_hdl := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.PARSE (v_cur_hdl, pQuery, DBMS_SQL.NATIVE);
      DBMS_SQL.DESCRIBE_COLUMNS (v_cur_hdl, oColCnt, oDescQry);
      DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
   EXCEPTION
      WHEN OTHERS
      THEN
         IF DBMS_SQL.IS_OPEN (v_cur_hdl)
         THEN
            DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
         END IF;

         MY_LOGGER.LOG ('MY_RULESENGINE.getColumnDesc',
                          'ERR',
                          SQLCODE,
                          'Exception in getColumnDesc Query : ' || pQuery,
                          '',
                          aLOGID,
                          'Exception');
         MY_LOGGER.LOG ('MY_RULESENGINE.getColumnDesc',
                          'ERR',
                          SQLCODE,
                          'Exception in getColumnDesc Error : ' || SQLERRM,
                          '',
                          aLOGID,
                          'Exception');
         RAISE;
   END getColumnDesc;

   PROCEDURE exeRuleQryAndGenOutput (
      pAppId           MY_RULE.APPID%TYPE,
      exeId            MY_RULE_OUTPUT.EXEID%TYPE,
      ruleId           MY_RULE_OUTPUT.RULE_ID%TYPE,
      ruleSetId        MY_RULE_OUTPUT.RULESET_ID%TYPE,
      parsedRuleQry    CLOB)
   AS
      v_cur_hdl      INT;
      ret            NUMBER;
      desctab        DBMS_SQL.DESC_TAB;
      colcnt         NUMBER;
      refDate        DATE;
      refTimeStamp   TIMESTAMP;
      refVarchar     VARCHAR2 (4000);
      refClob        CLOB;
      refNum         NUMBER;
      outputRow      MY_RULE_OUTPUT%ROWTYPE;
      rowCount       NUMBER := 1;
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :exeRuleQryAndGenOutput');
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:pAppId=' || pAppId);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:exeId=' || exeId);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:ruleId=' || ruleId);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:ruleSetId=' || ruleSetId);
      --DBMS_OUTPUT.PUT_LINE ('Parameter 1:parsedRuleQry=' || parsedRuleQry);
      v_cur_hdl := DBMS_SQL.OPEN_CURSOR;
      DBMS_SQL.PARSE (v_cur_hdl, parsedRuleQry, DBMS_SQL.NATIVE);
      DBMS_SQL.DESCRIBE_COLUMNS (v_cur_hdl, colcnt, desctab);

      FOR i IN 1 .. colcnt
      LOOP
         IF desctab (i).col_type = DBMS_TYPES.NO_DATA
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl,
                                    i,
                                    refVarchar,
                                    4000);
         ELSIF desctab (i).col_type IN (DBMS_TYPES.TYPECODE_DATE)
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refDate);
         ELSIF desctab (i).col_type IN
                  (181,
                   DBMS_TYPES.TYPECODE_TIMESTAMP,
                   DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ,
                   DBMS_TYPES.TYPECODE_TIMESTAMP_TZ)
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refTimeStamp);
         ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_NUMBER
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refNum);
         ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_CLOB
         THEN
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl, i, refClob);
         ELSE
            DBMS_SQL.DEFINE_COLUMN (v_cur_hdl,
                                    i,
                                    refVarchar,
                                    4000);
         END IF;
      END LOOP;

      ret := DBMS_SQL.EXECUTE (v_cur_hdl);

      LOOP
         IF DBMS_SQL.FETCH_ROWS (v_cur_hdl) > 0
         THEN
            SELECT MY_RULE_OUTPUT_SEQ.NEXTVAL
              INTO outputRow.outputid
              FROM DUAL;

            outputRow.appid := pAppId;
            outputRow.rule_id := ruleId;
            outputRow.RULESET_ID := ruleSetId;
            outputRow.exeid := exeId;
            outputRow.recid := rowCount;

            FOR i IN 1 .. colcnt
            LOOP
               outputRow.colIdx := i;
               outputRow.colName := desctab (i).col_name;
               outputRow.colType := TO_CHAR (desctab (i).col_type);
               outputRow.colval := NULL;
               outputRow.colval_dt := NULL;
               outputRow.colval_ts := NULL;
               outputRow.colval_cl := NULL;

               IF desctab (i).col_type = DBMS_TYPES.NO_DATA
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refVarchar);
                  outputRow.COLVAL := NULL;
               ELSIF desctab (i).col_type IN (DBMS_TYPES.TYPECODE_DATE)
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refDate);
                  outputRow.COLVAL :=
                     TO_CHAR (refDate, 'DD-MON-YYYY HH12.MI.SS AM');
                  outputRow.COLVAL_DT := refDate;
               ELSIF desctab (i).col_type IN
                        (181,
                         DBMS_TYPES.TYPECODE_TIMESTAMP,
                         DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ,
                         DBMS_TYPES.TYPECODE_TIMESTAMP_TZ)
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refTimeStamp);
                  outputRow.COLVAL :=
                     TO_CHAR (refTimeStamp, 'DD-MON-YYYY HH12.MI.SS AM');
                  outputRow.COLVAL_TS := refTimeStamp;
               ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_NUMBER
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refNum);
                  outputRow.COLVAL := TO_CHAR (refNum);
               ELSIF desctab (i).col_type = DBMS_TYPES.TYPECODE_CLOB
               THEN
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refClob);
                  outputRow.COLVAL := TO_CHAR (refClob);
                  outputRow.COLVAL_CL := refClob;
               ELSE
                  DBMS_SQL.COLUMN_VALUE (v_cur_hdl, i, refVarchar);
                  outputRow.COLVAL := refVarchar;
               END IF;

               INSERT INTO MY_RULE_OUTPUT
                    VALUES outputRow;
            END LOOP;
         ELSE
            EXIT;
         END IF;

         rowCount := rowCount + 1;
      END LOOP;

      DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
   EXCEPTION
      WHEN OTHERS
      THEN
         IF DBMS_SQL.IS_OPEN (v_cur_hdl)
         THEN
            DBMS_SQL.CLOSE_CURSOR (v_cur_hdl);
         END IF;

         MY_LOGGER.LOG ('MY_RULESENGINE.exeRuleQryAndGenOutput',
                          'ERR',
                          SQLCODE,
                          SQLERRM,
                          '-',
                          aLOGID,
                          'Error');
         RAISE;
   END exeRuleQryAndGenOutput;

   FUNCTION shouldBreak (pAppId     MY_RULE.APPID%TYPE,
                         pQuery     CLOB,
                         pExecId    MY_RULE_OUTPUT.EXEID%TYPE)
      RETURN BOOLEAN
   AS
      currParsedRuleQry   CLOB := NULL;
      currRow             RowData;
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :shouldBreak');

      MY_LOGGER.LOG ('MY_RULESENGINE.shouldBreak',
                       'DEB',
                       '0',
                       'Executing breakingConditionQuery:' || pQuery,
                       'ExecId',
                       pExecId,
                       aLOGID,
                       'Normal');
      currParsedRuleQry := parseQuery (pAppId, pQuery, pExecId);

      BEGIN
         SELECT * INTO currRow FROM TABLE (exeAnyQuery (currParsedRuleQry));

         IF (UPPER (TRIM (currRow (1))) IN ('Y', 'YES', 'T', 'TRUE', '1'))
         THEN
            RETURN TRUE;
         ELSE
            RETURN FALSE;
         END IF;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
            RETURN FALSE;
         WHEN OTHERS
         THEN
            MY_LOGGER.LOG ('MY_RULESENGINE.shouldBreak',
                             'ERR',
                             SQLCODE,
                             SQLERRM,
                             pExecId,
                             aLOGID,
                             'Error');
            RAISE;
      END;
   END shouldBreak;

   FUNCTION isSelectQuery (pParsedQuery CLOB)
      RETURN BOOLEAN
   AS
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :isSelectQuery');

      IF (REGEXP_INSTR (TRIM (pParsedQuery),
                        'select',
                        1,
                        1,
                        0,
                        'im')) = 1
      THEN
         RETURN TRUE;
      ELSE
         RETURN FALSE;
      END IF;
   END isSelectQuery;

   PROCEDURE exeAnyNonSelectQuery (
      pAppId           MY_RULE.APPID%TYPE,
      exeId            MY_RULE_OUTPUT.EXEID%TYPE,
      ruleId           MY_RULE_OUTPUT.RULE_ID%TYPE,
      ruleSetId        MY_RULE_OUTPUT.RULESET_ID%TYPE,
      parsedRuleQry    CLOB)
   AS
   BEGIN
      --DBMS_OUTPUT.PUT_LINE ('********* PROC :exeAnyNonSelectQuery');
      MY_LOGGER.LOG ('MY_RULESENGINE.exeAnyNonSelectQuery',
                       'ERR',
                       '0',
                       'Executing exeAnyNonSelectQuery:' || parsedRuleQry,
                       exeId,
                       ruleSetId,
                       ruleId,
                       aLOGID,
                       'Normal');

      EXECUTE IMMEDIATE TO_CHAR (parsedRuleQry);
   EXCEPTION
      WHEN OTHERS
      THEN
         MY_LOGGER.LOG ('MY_RULESENGINE.exeAnyNonSelectQuery',
                          'ERR',
                          SQLCODE,
                          SQLERRM,
                          exeId,
                          ruleSetId,
                          ruleId,
                          aLOGID,
                          'Error');
         RAISE;
   END exeAnyNonSelectQuery;
END MY_RULESENGINE;

--------------------------------------------------------------------

Test Run / Sample Program


/**
DMLs
***/
INSERT INTO MY_LOG_PROPERTIES (LOGGER,
                                 LOGLEVEL,
                                 CREATEDBY,
                                 CREATEDDT,
                                 UPDATEDT,
                                 UPDATEDBY)
    VALUES ('*',
             'ON',
             'Agilan',
             SYSDATE,
             SYSDATE,
             'Agilan');

INSERT INTO MY_LOG_PROPERTIES (LOGGER,
                                 LOGLEVEL,
                                 CREATEDBY,
                                 CREATEDDT,
                                 UPDATEDT,
                                 UPDATEDBY)
     VALUES ('MY_RULESENGINE',
             'DEB',
             'Agilan',
             SYSDATE,
             SYSDATE,
             'Agilan');

---------------

INSERT INTO MY_RULE_EXE_CONFIG (ID,
                                  APPID,
                                  RULESET_ID,
                                  BREAK_CONDN_BEF_AFT,
                                  BREAKING_RULEID,
                                  UPDDT)
     VALUES (MY_exe_rule_config_seq,
             'YourApplicationID',
             'YourRuleSetId',
             'AFT',
             'breakOnFailure',
             SYSDATE);

             INSERT INTO MY_RULE_BINDVARIABLES (APPID,
                                     VARIABLENAME,
                                     BIND_QUERY,
                                     INC_TYPE,
                                     CACHE_WITHIN_EXEC,
                                     UPDDT)
     VALUES (
               'YourApplicationID',
               '$v.input_param1_from_caller$',
               'SELECT value FROM MY_RE_INPUT_PARAM WHERE EXEID=$p.pExecId$  AND upper(KEY)=''PARAMETERNAME_1''',
               'EQ',
               'N',
               SYSDATE);
              
INSERT INTO MY_RULE_BINDVARIABLES (APPID,
                                     VARIABLENAME,
                                     BIND_QUERY,
                                     INC_TYPE,
                                     CACHE_WITHIN_EXEC,
                                     UPDDT)
     VALUES (
               'YourApplicationID',
               '$v.input_param2_list_from_caller$',
               'SELECT value FROM MY_RE_INPUT_PARAM WHERE EXEID=$p.pExecId$  AND upper(KEY)=''PARAMETERNAME_2_LIST''',
               'IN',
               'N',
               SYSDATE);
              
INSERT INTO MY_RULE_BINDVARIABLES (APPID,
                                     VARIABLENAME,
                                     BIND_QUERY,
                                     INC_TYPE,
                                     CACHE_WITHIN_EXEC,
                                     UPDDT)
     VALUES (
               'YourApplicationID',
               '$v.current_date$',
               'SELECT sysdate from dual',
               'EQ',
               'Y',
               SYSDATE);

INSERT INTO MY_RULE_BINDVARIABLES (APPID,
                                     VARIABLENAME,
                                     BIND_QUERY,
                                     INC_TYPE,
                                     CACHE_WITHIN_EXEC,
                                     UPDDT)
     VALUES (
               'YourApplicationID',
               '$v.somevariable1$',
               'SELECT ''data'' from dual',
               'EQ',
               'N',
               SYSDATE);
              
INSERT INTO MY_RULE (ID,
                       APPID,
                       RULE_ID,
                       RULESET_ID,
                       RULE_QUERY,
                       UPDATEDDT)
     VALUES (MY_rule_seq.NEXTVAL,
             'YourApplicationID',
             'breakOnFailure',
             'YourRuleSetId',
             'select ''1'' neverbreak from dual where 1=2 ',
             SYSDATE);

INSERT INTO MY_RULE (ID,
                       APPID,
                       RULE_ID,
                       RULESET_ID,
                       RULE_QUERY,
                       UPDATEDDT)
     VALUES (
               MY_rule_seq.NEXTVAL,
               'YourApplicationID',
               'MyRuleQuery1',
               'YourRuleSetId',
               ' select col1,col2,col3 from some_table where some_col = $v.somevariable1$',
               SYSDATE);

INSERT INTO MY_RULE (ID,
                       APPID,
                       RULE_ID,
                       RULESET_ID,
                       RULE_QUERY,
                       UPDATEDDT)
     VALUES (
               MY_rule_seq.NEXTVAL,
               'YourApplicationID',
               'MyRuleQuery2',
               'YourRuleSetId',
               '  select col1,col2,col3 from some_other_table where some_date_col = $v.current_date$ ',
               SYSDATE);

INSERT INTO MY_RULE (ID,
                       APPID,
                       RULE_ID,
                       RULESET_ID,
                       RULE_QUERY,
                       UPDATEDDT)
     VALUES (
               MY_rule_seq.NEXTVAL,
               'YourApplicationID',
               'MyRuleQuery3',
               'YourRuleSetId',
               '  select col1,col2,col3 from some_other_table where some_col = $v.input_param1_from_caller$ ',
               SYSDATE);

INSERT INTO MY_RULE (ID,
                       APPID,
                       RULE_ID,
                       RULESET_ID,
                       RULE_QUERY,
                       UPDATEDDT)
     VALUES (
               MY_rule_seq.NEXTVAL,
               'YourApplicationID',
               'MyRuleQuery4',
               'YourRuleSetId',
               '  select col1,col2,col3 from some_other_table where some_col in $v.input_param2_list_from_caller$ ',
               SYSDATE);
              
-----------------------
/** Testing the proc **/

begin
    /** Insert input_param and execute the proc in the same session **/
    insert into MY_RE_INPUT_PARAM (exeid,key,value) values ( 1, 'PARAMETERNAME_1','apple');
    insert into MY_RE_INPUT_PARAM (exeid,key,value) values ( 1, 'PARAMETERNAME_2_LIST','apple');
    insert into MY_RE_INPUT_PARAM (exeid,key,value) values ( 1, 'PARAMETERNAME_2_LIST','mango');
    insert into MY_RE_INPUT_PARAM (exeid,key,value) values ( 1, 'PARAMETERNAME_2_LIST','banana');
    insert into MY_RE_INPUT_PARAM (exeid,key,value) values ( 1, 'PARAMETERNAME_2_LIST','avacado');

    MY_RULESENGINE.pub_fireRules('YourApplicationId','YourRuleSetId',1);
   
end;


Viewing all articles
Browse latest Browse all 318

Trending Articles