Modernisation Oracle Forms

Code pour convertir automatiquement les déclencheurs POST-QUERY en procédures

Aperçu

Ce code apporte une solution aux problèmes signalés dans Bug:1702454 et BUG:1396180, liés aux changements dans la gestion des curseurs entre Forms 4.5 et 6i. Dans Forms 6i, les curseurs déclarés dans les déclencheurs sont automatiquement fermés à la fin du déclencheur. Dans Forms 4.5, au contraire, les curseurs sont simplement annulés, et non fermés. Cette fermeture du curseur a un avantage et un inconvénient. L'avantage : l'utilisation des ressources de la base de données diminue, puisque les curseurs ne restent pas dans la SGA en attendant d'être réutilisés. L'inconvénient : si le curseur est de nouveau nécessaire, il doit être analysé (parse) et rouvert avant de pouvoir être exécuté une autre fois, ce qui a un coût en temps. Dans certains cas, comme l'utilisation de curseurs dans des déclencheurs POST-QUERY, qui s'exécutent pour chaque ligne renvoyée par la base de données, les performances peuvent donc se dégrader considérablement après la mise à niveau vers Forms 6i (même si, en contrepartie, l'utilisation des ressources de la base de données aura diminué). Heureusement, il existe un moyen simple de revenir au comportement de la version 4.5, où les curseurs sont simplement annulés plutôt que fermés. Dans Forms 6i, si vous codez les curseurs dans des unités de programme (Program Units) PL/SQL plutôt que dans des déclencheurs, le curseur n'est pas fermé à la fin de l'unité de programme. Vous pouvez ainsi déplacer le curseur dans une procédure PL/SQL que vous appelez ensuite depuis le déclencheur POST-QUERY d'origine, ce qui rétablit le profil de performance de l'application 4.5. Bien entendu, si vous avez un grand nombre de déclencheurs de ce type à traiter, le travail peut être long. Le code présenté dans cet article est un programme basé sur l'API Forms qui automatise pour vous cette migration du code.

Notes sur le programme

Le code fourni est conçu pour être compilé sous Windows 32 bits avec Microsoft Visual C++ version 5.0 ou 6.0. Le programme pourrait être adapté à UNIX au besoin, moyennant quelques modifications de la gestion des chaînes de caractères.

Le fichier C doit être compilé et lié avec le fichier ifd2f60.lib, qui se trouve, avec tous les fichiers d'en-tête requis, dans le répertoire %ORACLE_HOME%/forms60/API.
Pour en savoir plus sur la création de programmes basés sur l'API Forms, consultez http://www.oracle.com/technetwork/developer-tools/forms/documentation/274326-134740.pdf

Tel que fourni, le programme accepte quatre arguments de ligne de commande, dont les deux premiers sont obligatoires.
Le premier argument est le nom du formulaire (Form) à traiter. Le deuxième argument est la chaîne de connexion à la base de données nécessaire pour compiler le formulaire. Le troisième argument est une chaîne contenant une partie ou la totalité des lettres "FBIP", qui indiquent où le programme doit chercher les déclencheurs POST-QUERY :
F = Recherche au niveau du formulaire (Form)
B = Recherche au niveau du bloc (Block)
I = Recherche dans les déclencheurs de niveau élément (Item)
P = Recherche dans les classes de propriétés (Property Classes)

La valeur par défaut est FBIP, c'est-à-dire toutes les options ci-dessus. Le dernier argument est un indicateur de test : indiquez Y comme dernier argument, et le programme vérifiera les déclencheurs candidats et en fera rapport sans effectuer réellement la modification.

Le programme écrit sa sortie dans un fichier portant le même nom que le formulaire, mais avec l'extension TXT.

Pendant le traitement, si un déclencheur POST-QUERY contenant un curseur ou une instruction SELECT est rencontré, une nouvelle unité de programme nommée <OBJECTNAME>_POST_QUERY est créée ; elle sera appelée depuis le déclencheur POST-QUERY d'origine.
REMARQUE : si plusieurs objets portent le même nom (p. ex. un BLOCK et un ITEM), la conversion échouera. Vous devrez alors modifier ce code pour qu'il génère des noms uniques.

Références

Bug 1702454 - DÉGRADATION DES PERFORMANCES CAUSÉE PAR UN TRAFIC RÉSEAU SUPPLÉMENTAIRE APRÈS LA MISE À NIVEAU VERS 6.0
Bug 1396180 - DÉGRADATION DES PERFORMANCES CAUSÉE PAR UN TRAFIC RÉSEAU SUPPLÉMENTAIRE APRÈS LA MISE À NIVEAU VERS 6.0

Mise en garde

Le programme d'exemple présenté dans cet article est fourni à des fins éducatives seulement et n'est PAS pris en charge par Oracle Support Services. Il a toutefois été testé à l'interne et fonctionne comme documenté. Nous ne garantissons pas qu'il fonctionnera dans votre cas : testez-le donc dans votre environnement avant de vous y fier.

Faites toujours des copies de sauvegarde de vos modules Forms avant d'exécuter des programmes API sur ceux-ci.

Programme

/***************************************************************************************/
/*                                                                                     */
/*   NAME                                                                              */
/*      RewritePostQuery                                                               */
/*                                                                                     */
/*   DESCRIPTION                                                                       */
/*      Looping through each Form's trigger to detect SELECT and CURSOR clause         */
/*      Creating a Program Unit for each trigger dectected with the trigger's code     */
/*      Transforming CURSOR structure into SELECT ...INTO structure                    */
/*      Calling Program Unit in trigger's code                                         */
/*                                                                                     */
/*   Command line syntax is:                                                           */
/*         <program name> <filename> <user/password@connectString> [FBIP]              */
/*            F = Searching into Form Level Trigger                                    */
/*            B = Searching into Block Level Trigger                                   */
/*            I = Searching into Item Level Trigger                                    */
/*            P = Searching into Property Class                                        */
/*            => Can be combined                                                       */
/*            [Y|N]                                                                    */
/*            Y = Report on candidate triggers but don't make the change               */
/*            N = (default) make the change
/*                                                                                     */
/*   Public FUNCTION(S)                                                                */
/*       enableComponents  =>                                                          */
/*       detectSelect      =>                                                          */
/*       detectCursor      =>                                                          */
/*       set_puName        =>                                                          */
/*       createProgramUnit =>                                                          */
/*       IsV2Style         =>                                                          */
/*                                                                                     */
/*   PRIVATE FUNCTION(S)                                                               */
/*       append_BeginEnd   =>                                                          */
/*       strcasestr        =>                                                          */
/*       strncasecmp       =>                                                          */
/*                                                                                     */
/*   MODIFIED                                                                          */
/*      mdurouss 10/14/2001 -  Creation                                                */
/*      mdurouss 11/02/2001 -  Test only Block's trigger POST-QUERY                    */
/*                          -  Don't transform Trigger's code in Uppercase             */
/*                          => Add strcasestr & strncasecmp functions                  */
/*      mdurouss 11/04/2001 -  Correction %NOTFOUND & %FOUND treatment                 */
/*                             carriage return in case of comments in Select & Into    */
/*                          -  Correction CursorFetchList & CursorSelectList to hold   */
/*                          -  Correction searching strings "INTO " or "INTO\n"        */
/*                          -  Correction size of Arrays for Cursor Lists from 10 to 20*/
/*                          -  Treatment of cursor opened more than one time           */
/*                             regarding cursor name declared more than one time but   */
/*                             for different SELECT statement                          */
/*      mdurouss 11/09/2001 -  Correction searching strings "CURSOR " or "CURSOR\t"    */
/*                             "SELECT " or "SELECT\n"or "SELECT\t","FROM " or "FROM\n"*/
/*                             "FROM\t","WHERE " or "WHERE\n" or "WHERE\t"             */
/*                          -  Correction for commented cursors , adding comment around*/
/*                             the new block BEGIN .... END;                           */
/*                          -  Writing output into a file                              */
/*      drmills  02/21/2002 -  Redirect initial output to stderr to prevent exception  */
/*                             when no arguments are supplied. Cleaned up              */
/***************************************************************************************/
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <d2ferr.h>
#include <d2fctx.h>
#include <d2ffmd.h>
#include <d2fblk.h>
#include <d2fitm.h>
#include <d2falt.h>
#include <d2ftrg.h>
#include <d2frdb.h>
#include <d2fdef.h>
#include <d2fpgu.h>
#include <d2fppc.h>


#define BUFSIZE 128
#define SUCCESS 0
#define FAIL 1
#define PUNAMEMAXLENGTH  28

int set_puName(char * name, char *sourceObject, char *triggerType);
int append_BeginEnd(char *puCodeIn, char *progUnitNameIn, char *triggerCodeIn);
int createProgramUnit(char *progUnitName,
            d2fctx *pd2fctx,
            d2ffmd *pd2ffmd,
            d2ftrg *pd2ftrg,
            char *triggerCode);
int enableComponents(char *componentFlag);
int IsV2Style(d2fctx *pd2fctx,d2ftrg *pd2ftrg);
int detectSelect(char *triggerCode);
int detectCursor(char *triggerCode);
char * strcasestr (char * s1, char * s2);
int strncasecmp (char * a, char * b, int n);


int FORM = FALSE;
int BLOCK = FALSE;
int ITEM = FALSE;
int PROPERTYCLASS = FALSE;

int PU_uniqueCounter = 1;

FILE *output = stderr;

int main (int argc, char * argv[])
{
  d2fctx   *pd2fctx;
  d2ffmd   *pd2ffmd;
  d2ftrg   *pd2ftrg;
  d2fblk   *pd2fblk;
  d2fitm   *pd2fitm;
  d2fctxa   d2fctx_attr;
  d2fstatus status;
  d2fppc   *pd2fppc;

  char      buf[BUFSIZE];
  char     *pd2ffmd_name=(char*)0;
  int       item_count = 0;
  int       cSize=0;
  char     *triggerCode;
  char     *name, *triggerName;
  char     *progUnitName;
  int       flagSelects = FALSE;
  text*     output_name = (char*)0;

  fprintf(output,"%s\n",argv[0]);

  switch (argc)
  {
    case (3) :
      enableComponents("FBIP");
      break;
    case (4) :
      enableComponents(argv[3]);
      break;
        case (5) :
            if ( strcmp(argv[4], "Y")==0 || strcmp(argv[4], "y")==0 )
            {
                flagSelects = TRUE;
                enableComponents(argv[3]);
            }
            else
            {
               enableComponents(argv[3]);
            }
            break;
    default :
      fprintf(output,"\n\tNot enough or too many arguments !\n");
      fprintf(output,"Usage : %s <form.fmb> <un/pw[@db]> [FBIP] [Y|y]\n\n", argv[0]);
      exit(1);
  }


    strncpy(buf, argv[1], BUFSIZE);
    pd2ffmd_name = strtok(buf, ".");

    /* Create text file for output */
    output_name = calloc(1,strlen(argv[1]));
    strcpy(output_name,pd2ffmd_name);
    strcat(output_name,".txt");
    output = fopen(output_name,"w");

    /* Initialize the attribute mask */
    d2fctx_attr.mask_d2fctxa = 0;

    /* Create the API context */
    status = d2fctxcr_Create(&pd2fctx, &d2fctx_attr);

    if ( (strcmp(argv[2], "NO")== 0) || (strcmp(argv[2], "no")==0) )
  {
    fprintf(output,"Connection not attempted.\n");
  }
  else
  {
    if( SUCCESS != d2fctxcn_Connect( pd2fctx, argv[ 2 ], ( dvoid * ) NULL ))
    {
      fprintf(output,"%s: Error connection failed for %s...\n", argv[ 0 ], argv[ 2 ] );
      exit(1);
    }
  }

    if ( flagSelects )
    {
        fprintf(output,"Checking trigger code for the word select (case-insensitive)\n");
    }
  /* Load the pd2ffmd */
    status = d2ffmdld_Load(pd2fctx, &pd2ffmd, pd2ffmd_name, FALSE);

  if (status==SUCCESS)
    {
        /*** Process Form Level Trigger  ***/

    if (FORM == TRUE)
    {
      for(status = d2ffmdg_trigger(pd2fctx,pd2ffmd,&pd2ftrg); pd2ftrg != NULL;
      status = d2ftrgg_next(pd2fctx,pd2ftrg,&pd2ftrg))
      {
        if (IsV2Style(pd2fctx,pd2ftrg) == FALSE)
        {
          d2ffmdg_name(pd2fctx, pd2ffmd, &name);
          d2ftrgg_name(pd2fctx, pd2ftrg, &triggerName);
            if (d2ftrgis_IsSubclassed(pd2fctx,pd2ftrg) == D2FS_NO)
          {
            d2ftrgg_trg_txt(pd2fctx, pd2ftrg, &triggerCode);

                        if ( flagSelects )
                        {
                            if ( detectSelect(triggerCode) )
                            {
                                fprintf(output,"%s:%s trigger code contains the words \"select\" and \"from\"\n",
                                       name, triggerName);
                            }
                        }
                        else
                        {
                            if ( detectSelect(triggerCode) )
                            {
                    //Create a program unit
                    progUnitName = malloc(strlen(name) + strlen(triggerName) + 1);
                    set_puName(progUnitName, name, triggerName);
                    createProgramUnit(progUnitName, pd2fctx, pd2ffmd, pd2ftrg, triggerCode);
                            }
                        }

            //free(progUnitName);

            //Done processing form level triggers !
          }
          else
          {
            fprintf(output,"Form level trigger %s.%s is subclassed...ignoring.\n",
                   name, triggerName);
          }
        }
      }
    } // FORM == TRUE

        // Loop round all blocks
        for(status = d2ffmdg_block(pd2fctx,pd2ffmd,&pd2fblk);
        pd2fblk != NULL;
        status = d2fblkg_next(pd2fctx,pd2fblk,&pd2fblk))
    {
      d2fblkg_name(pd2fctx, pd2fblk, &name);
      fprintf(output,"\n\tProcessing block : %s\n", name);

      if (BLOCK == TRUE)
      {
          /* Process Block Level Trigger  */
        for(status = d2fblkg_trigger(pd2fctx,pd2fblk,&pd2ftrg); pd2ftrg != NULL;
        status = d2ftrgg_next(pd2fctx,pd2ftrg,&pd2ftrg))
        {
          if (IsV2Style(pd2fctx,pd2ftrg) == FALSE)
          {
                d2fblkg_name(pd2fctx, pd2fblk, &name);
            d2ftrgg_name(pd2fctx, pd2ftrg, &triggerName);
            if (!strcmp(triggerName,"POST-QUERY"))
            {
              if (d2ftrgis_IsSubclassed(pd2fctx,pd2ftrg) == D2FS_NO)
              {
                d2ftrgg_trg_txt(pd2fctx, pd2ftrg, &triggerCode);

                if ( flagSelects )
                {
                  if ( detectSelect(triggerCode) )
                  {
                   fprintf(output,"%s:%s trigger code contains the word 'select'\n",
                      name, triggerName);
                    }
                  }
                else
                {
                 if ( detectSelect(triggerCode) )
                 {

                   // Create a program unit containing the trigger code.
                  progUnitName = malloc(strlen(name) + strlen(triggerName) + 1);
                  set_puName(progUnitName, name, triggerName);
                        createProgramUnit(progUnitName, pd2fctx, pd2ffmd, pd2ftrg, triggerCode);
                  }
                }
                //free(progUnitName);

                //Done processing form block triggers !
              }
              else
              {
               fprintf(output,"\tBlock level trigger %s.%s is subclassed...ignoring.\n",
                       name, triggerName);
              }
            }
          }
        }
      } // BLOCK == TRUE


      if (ITEM == TRUE)
      {
        // Loop through all items
            for(status = d2fblkg_item(pd2fctx,pd2fblk,&pd2fitm);
          pd2fitm != NULL;
        status = d2fitmg_next(pd2fctx,pd2fitm,&pd2fitm))
        {
          d2fitmg_name(pd2fctx, pd2fitm, &name);
          fprintf(output,"\t\tProcessing item : %s\n", name);

          // Process Item Level Triggers
              for(status = d2fitmg_trigger(pd2fctx,pd2fitm,&pd2ftrg);
            pd2ftrg != NULL;
              status = d2ftrgg_next(pd2fctx,pd2ftrg,&pd2ftrg))
          {
            if (IsV2Style(pd2fctx,pd2ftrg) == FALSE)
            {
                  d2fitmg_name(pd2fctx, pd2fitm, &name);
                d2ftrgg_name(pd2fctx, pd2ftrg, &triggerName);
              if (d2ftrgis_IsSubclassed(pd2fctx,pd2ftrg) == D2FS_NO)
              {
                        d2ftrgg_trg_txt(pd2fctx, pd2ftrg, &triggerCode);

                                if ( flagSelects )
                                {
                                    if ( detectSelect(triggerCode) )
                                    {
                                        fprintf(output,"%s:%s trigger code contains the word 'select'\n",
                                         name, triggerName);
                                    }
                                }
                                else
                                {
                                    if ( detectSelect(triggerCode) )
                                    {
                        // Create a program unit containing the trigger code.
                        progUnitName = malloc(strlen(name) + strlen(triggerName) + 1);
                        set_puName(progUnitName, name, triggerName);
                        createProgramUnit(progUnitName, pd2fctx, pd2ffmd, pd2ftrg, triggerCode);
                                    }
                                }
                //free(progUnitName);

                //Done processing form block triggers !

              }
              else
              {
                    fprintf(output,"\t\t\tItem level trigger %s.%s is subclassed...ignoring.\n",
                       name, triggerName);
              }
            }
          }
        }
      } // ITEM == TRUE
    }

    // Finally process property classes...

    // Loop round all property classes
    if (PROPERTYCLASS == TRUE)
    {
          for(status = d2ffmdg_prop_class(pd2fctx,pd2ffmd,&pd2fppc);
        pd2fppc != NULL;
      status = d2fppcg_next(pd2fctx,pd2fppc,&pd2fppc))
      {
        d2fppcg_name(pd2fctx, pd2fppc, &name);
        fprintf(output,"\n\tProcessing property class : %s\n", name);

          //loop round all triggers in property class...
        for(status = d2fppcg_trigger(pd2fctx,pd2fppc,&pd2ftrg); pd2ftrg != NULL;
        status = d2ftrgg_next(pd2fctx,pd2ftrg,&pd2ftrg))
        {
          if (IsV2Style(pd2fctx,pd2ftrg) == FALSE)
          {
            d2fppcg_name(pd2fctx, pd2fppc, &name);
            d2ftrgg_name(pd2fctx, pd2ftrg, &triggerName);
            if (d2ftrgis_IsSubclassed(pd2fctx,pd2ftrg) == D2FS_NO)
            {
                d2ftrgg_trg_txt(pd2fctx, pd2ftrg, &triggerCode);

                            if ( flagSelects )
                            {
                                if ( detectSelect(triggerCode) )
                                {
                                    fprintf(output,"%s:%s trigger code contains the word 'select'\n",
                                       name, triggerName);
                                }
                            }
                            else
                            {
                  // Create a program unit containing the trigger code.
                  progUnitName = malloc(strlen(name) + strlen(triggerName) + 1);
                  set_puName(progUnitName, name, triggerName);
                  createProgramUnit(progUnitName, pd2fctx, pd2ffmd, pd2ftrg, triggerCode);
                            }
                //free(progUnitName);

              //Done processing form block triggers !
            }
            else
            {
                fprintf(output,"\t\t\tProperty class trigger %s.%s is subclassed...ignoring.\n",
              name, triggerName);
            }
          }
        }
      }
    } // PROPERTYCLASS == TRUE

        // Save out the pd2ffmd
        if (status = d2ffmdsv_Save(pd2fctx, pd2ffmd, (text *)0, FALSE) != SUCCESS)
    {
      fprintf(output,"Unable to save form %s\n", pd2ffmd_name);
      exit(1);
    }

    // Generate the pd2ffmds executable (fmx)

        if (status = d2ffmdcf_CompileFile(pd2fctx, pd2ffmd ) != SUCCESS)
    {
      fprintf(output,"Unable to generate form %s\n", pd2ffmd_name);
      exit(1);
    }


    /* Destroy the API Context */
    if (status = d2fctxde_Destroy(pd2fctx) != SUCCESS)
    {
      fprintf(output,"Unable to destroy context for form %s\n", pd2ffmd_name);
      exit(1);
    }
    fprintf(output,"\nFinished");
	fprintf(stderr,"Finished\n");
    return 0;

    } //status == SUCCESS

  else
  {
    fprintf(output,"Unable to load form\n");
    exit(0);
  }
}

///////////////////////////////////////////////////////////////////////////////////

int set_puName(char * name, char *sourceObject, char *triggerType)
{
  int i;
  char tempName[PUNAMEMAXLENGTH-4];

  for (i=0; (size_t)i < strlen(triggerType); i++)
  {
    if (triggerType[i] == '-')
      triggerType[i] = '_';
  }

  strcpy(name, sourceObject);
  strcat(name, "_");
  strcat(name, triggerType);
  if (strlen(name) > PUNAMEMAXLENGTH)
  {
    name[PUNAMEMAXLENGTH - 4] = '\0';
        strcpy(tempName, name);

    sprintf(name, "%s%04d\0", tempName, PU_uniqueCounter);
    PU_uniqueCounter++;
  }
  return SUCCESS;
}

////////////////////////////////////////////////////////////////////////////////////
int append_BeginEnd(char *puCodeIn, char *progUnitNameIn, char *triggerCodeIn)
{
  strcpy(puCodeIn, "PROCEDURE ");
  strcat(puCodeIn, progUnitNameIn);
  strcat(puCodeIn, " IS\nBEGIN\n");
  strcat(puCodeIn, triggerCodeIn);
  strcat(puCodeIn, "\nEND;");
  return (SUCCESS);
}

////////////////////////////////////////////////////////////////////////////////////
int createProgramUnit(char *progUnitName,
            d2fctx *pd2fctx,
            d2ffmd *pd2ffmd,
            d2ftrg *pd2ftrg,
            char *triggerCode)

{
  d2fpgu   *pd2fpgu;
  int       status;
  char     *puCode;
  int       i=0, j=0, k=0, l=-1, m=0, n=0, ncur=0, o=0, p=0, found=0, ind=0, cns=0 , co=0;
  int       lg_puCodeDest = 0;
  const int NBCUR = 20;
  text     *pdest_exe;
  char     *puCodeDest;
  char     *puCodeFinal;
  char      fetchName[100];
  char     *cursorName[20];
  char     *cursorFetchList[20];
  char     *cursorFetchFound[20];
  char     *cursorCommented[20];
  char     *cursorSelectList[20];
  char     *cursorFromClause[20];

  fprintf(output,"Generating program unit %s\n", progUnitName);

    if (status = d2fpgucr_Create(pd2fctx, pd2ffmd, &pd2fpgu, (text *)progUnitName)!=SUCCESS)
    {
    fprintf(output,"Unable to create program unit $s\n", progUnitName);
    exit(1);
    }

    // set the type of the PU
    if (status=d2fpgusn_SetNumProp(pd2fctx, pd2fpgu, D2FP_PGU_TYP, D2FC_PGTY_PROCEDURE) !=SUCCESS)
  {
    fprintf(output,"Unable to set PU type for program unit $s\n", progUnitName);
    exit(1);
  }

  //Put the extra stuff around the code...
  puCode=(char *)calloc(1,(strlen(progUnitName) + strlen(triggerCode) +30));
  memset(puCode, '\0', (strlen(progUnitName) + strlen(triggerCode) +30));
    append_BeginEnd(puCode, progUnitName, triggerCode);

  puCodeDest=calloc(1,(strlen(progUnitName) + strlen(triggerCode) + 100));
  memset(puCodeDest, '\0', (strlen(progUnitName) + strlen(triggerCode) + 100));
  puCodeFinal=(char *)calloc(1,(strlen(progUnitName) + strlen(triggerCode) + 100));
  memset(puCodeFinal, '\0', (strlen(progUnitName) + strlen(triggerCode) + 100));

    // Set the PU text
  if (detectCursor(puCode))
  {

    for (i=0; i<30; i++)
      fetchName[i] = '\0';

    for (i=0; i<NBCUR; i++)
    {
      cursorFetchList[i]=calloc(1,2000);
      memset(cursorFetchList[i], '\0',2000);
      cursorFetchFound[i]=calloc(1,10);
      memset(cursorFetchFound[i], '\0',10);
      cursorCommented[i]=calloc(1,10);
      memset(cursorCommented[i], '\0',10);
      cursorSelectList[i]=calloc(1,2000);
      memset(cursorSelectList[i], '\0',2000);
      cursorFromClause[i]=calloc(1,2000);
      memset(cursorFromClause[i], '\0',2000);
      cursorName[i]=calloc(1,30);
      memset(cursorName[i], '\0',30);
    }

    pdest_exe = strcasestr( puCode, "CURSOR" );

    if (pdest_exe != NULL)
    {
      for(i=0,j=0;i<(int)(strlen(puCode));i++)
      {
        if (((!strncasecmp(&puCode[i],"CURSOR ",strlen("CURSOR "))) ||
           (!strncasecmp(&puCode[i],"CURSOR\t",strlen("CURSOR\t")))) &&
          (strncmp(&puCode[i-1],"_",strlen("_"))))
        {
          // Checking if cursor is commented
          found = 0;
          for (co=i-1; co >=0; co--)
          {
            if ((puCode[co] == '*') && (puCode[co-1] == '/'))
            {
              found = 1;
              break;
            }
            else if ((puCode[co] != '\n') &&
                   (puCode[co] != '\t') &&
                   (puCode[co] != ' '))
            {
              found = 0;
              break;
            }
          }
          l++;
          m=0;
          i += 7;
          for(k=i; k<(int)strlen(puCode); k++)
          {
            if(!strncasecmp(&puCode[k]," IS",strlen(" IS")))
            {
              cursorName[l][m]='\0';
              if (found == 1)
                cursorCommented[l][0]='*';
              else
                cursorCommented[l][0] = ' ';
              i+=3;
              break;
            }
            else
            {
              if ((puCode[k] != ' ') && (puCode[k] != '\t') )
              {
                cursorName[l][m++]=puCode[k];
              }
            i++;
            }
          }
          found=0;
          for(k=i; k<(int)strlen(puCode); k++)
          {
            if((!strncasecmp(&puCode[k],"SELECT ",strlen("SELECT "))) ||
               (!strncasecmp(&puCode[k],"SELECT\n",strlen("SELECT\n"))) ||
               (!strncasecmp(&puCode[k],"SELECT\t",strlen("SELECT\t"))))
            {
              for (p=k; p>=0; p--)
              {
                if (puCode[p]=='\n')
                  break;
                if (!strncasecmp(&puCode[p],"'",1))
                {
                  found=1;
                }
              }
              if (found==0)
              {
                m=0;
                for(n=k; n<(int)strlen(puCode); n++)
                {
                  if((!strncasecmp(&puCode[n],"FROM ",strlen("FROM "))) ||
                           (!strncasecmp(&puCode[n],"FROM\n",strlen("FROM\n"))) ||
                     (!strncasecmp(&puCode[n],"FROM\t",strlen("FROM\t"))))
                  {
                    cursorSelectList[l][m]='\0';
                    i+=5;
                    m=0;
                    for(o=n; o<(int)strlen(puCode); o++)
                    {
                      if(!strncasecmp(&puCode[o],";",1))
                      {
                        cursorFromClause[l][m]='\0';
                        i = o + 1;
                        break;
                      }
                      else
                      {
                        cursorFromClause[l][m++]=puCode[o];
                      }
                    }
                    break;
                  }
                  else
                  {
                    cursorSelectList[l][m++]=puCode[n];
                    i++;
                  }
                }
                break;
              }
              else
                found=0;
            }
          }
        }
      }
      for(i=0,j=0;i<(int)(strlen(puCode));i++)
      {
        if ((!strncasecmp(&puCode[i],"FETCH ",strlen("FETCH "))) ||
          (!strncasecmp(&puCode[i],"FETCH\n",strlen("FETCH\n"))) ||
          (!strncasecmp(&puCode[i],"FETCH\t",strlen("FETCH\t"))))
        {
          m=0;
          i += 6;
          for(k=i; k<(int)strlen(puCode); k++)
          {
            if((!strncasecmp(&puCode[k],"INTO ",strlen("INTO "))) ||
               (!strncasecmp(&puCode[k],"INTO\n",strlen("INTO\n"))) ||
               (!strncasecmp(&puCode[k],"INTO\t",strlen("INTO\t"))))
            {
              fetchName[m]='\0';
              break;
            }
            else
            {
              if (puCode[k] != ' ')
                fetchName[m++]=puCode[k];
            }
          }
          found = 0;
          for (n=0; n<NBCUR; n++)
          {
            if (cursorName[n][0] == '\0')
              break;
            else if (cursorFetchFound[n][0]!='*')
            {
              if (!strncasecmp(cursorName[n],fetchName,strlen(cursorName[n])))
              {
                found = 1;
                ncur = n;
                cursorFetchFound[ncur][0]='*';
                break;

              }
            }
          }
          if (found == 0)
          {
            for (n=0; n<NBCUR; n++)
            {
              if (cursorFetchFound[n][0]=='*')
              {
                if (!strncasecmp(cursorName[n],fetchName,strlen(cursorName[n])))
                {
                  ncur = n;
                  break;
                }
              }
            }
          }
          else
            found = 0;
          m=0;
          for(l=k+5; l<(int)strlen(puCode); l++)
          {
            if(!strncasecmp(&puCode[l],";",strlen(";")))
            {
              cursorFetchList[ncur][m]='\0';
              break;
            }
            else
            {
            
                cursorFetchList[ncur][m++]=puCode[l];
            }
          }
        }
      }
      for (p=0;p<NBCUR;p++)
      {
        cursorFetchFound[p][0]=' ';
      }
      m=0;
      for(i=0,j=0;i<(int)(strlen(puCode));i++)
      {
        if (((!strncasecmp(&puCode[i],"CURSOR ",strlen("CURSOR "))) ||
           (!strncasecmp(&puCode[i],"CURSOR\t",strlen("CURSOR\t")))) &&
          (strncmp(&puCode[i-1],"_",strlen("_"))))
        {
          i += 7;
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if(!strncasecmp(&puCode[k]," IS",strlen(" IS")))
            {
              i += 3;
              fetchName[m]='\0';
              m=0;
              break;
            }
            else
              if (puCode[k] != ' ' )
                fetchName[m++]=puCode[k];
              i++;
          }
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if( puCode[k] == ';')
            {
              i +=1;
              break;
            }
            else
              i++;
          }
        }
        else if ((!strncasecmp(&puCode[i],"OPEN ",strlen("OPEN "))) ||
             (!strncasecmp(&puCode[i],"OPEN\n",strlen("OPEN\n"))) ||
             (!strncasecmp(&puCode[i],"OPEN\t",strlen("OPEN\t"))))
        {
          i += 5;
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if(!strncasecmp(&puCode[k],";",strlen(";")))
            {
              i +=1;
              break;
            }
            else
              i++;
          }
        }
        else if ((!strncasecmp(&puCode[i],"CLOSE ",strlen("CLOSE "))) ||
             (!strncasecmp(&puCode[i],"CLOSE\n",strlen("CLOSE\n"))) ||
             (!strncasecmp(&puCode[i],"CLOSE\t",strlen("CLOSE\t"))))
        {
          i += 6;
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if(!strncasecmp(&puCode[k],";",strlen(";")))
            {
              i +=1;
              puCodeDest[j++]='\n';
              break;
            }
            else
              i++;
          }
        }

        else if ((!strncasecmp(&puCode[i],"FETCH ",strlen("FETCH "))) ||
             (!strncasecmp(&puCode[i],"FETCH\n",strlen("FETCH\n"))) ||
             (!strncasecmp(&puCode[i],"FETCH\t",strlen("FETCH\t"))))
        {
          i += 6;
          m=0;
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if((!strncasecmp(&puCode[k],"INTO ",strlen("INTO "))) ||
               (!strncasecmp(&puCode[k],"INTO\n",strlen("INTO\n"))) ||
               (!strncasecmp(&puCode[k],"INTO\t",strlen("INTO\t"))))
            {
              fetchName[m]='\0';
              m=0;
              break;
            }
            else
              if (puCode[k] != ' ')
                fetchName[m++]=puCode[k];
          }
          for (k=i; k<(int)strlen(puCode);k++)
          {
            if(!strncasecmp(&puCode[k],";",strlen(";")))
            {
              found = 0;
              for (n=0; n<NBCUR; n++)
              {
                if (cursorName[n][0] == '\0')
                  break;
                else if (cursorFetchFound[n][0]!='*')
                {
                  if (!strncasecmp(cursorName[n],fetchName,strlen(cursorName[n])))
                  {
                    found = 1;
                    ncur = n;
                    cursorFetchFound[ncur][0]='*';
                    break;
                  }
                }
              }
              if (found == 0)
              {
                for (n=0; n<NBCUR; n++)
                {
                  if (cursorFetchFound[n][0]=='*')
                  {
                    if (!strncasecmp(cursorName[n],fetchName,strlen(cursorName[n])))
                    {
                      ncur = n;
                      break;
                    }
                  }
                }
              }
              else
                found = 0;
              // MD - 26/10/2001
              if (cursorCommented[ncur][0] == '*')
              {
                puCodeDest[j++] = '\n';
                puCodeDest[j++] = '/';
                puCodeDest[j++] = '*';
                puCodeDest[j++] = '\n';
              }
              puCodeDest[j++] = 'B';
              puCodeDest[j++] = 'E';
              puCodeDest[j++] = 'G';
              puCodeDest[j++] = 'I';
              puCodeDest[j++] = 'N';
              puCodeDest[j++] = '\n';
              // MD - 26/10/2001
              for (n=0; n<(int)strlen(cursorSelectList[ncur]);n++)
              {
                puCodeDest[j++]=cursorSelectList[ncur][n];
              }
              puCodeDest[j++]='I';
              puCodeDest[j++]='N';
              puCodeDest[j++]='T';
              puCodeDest[j++]='O';
              puCodeDest[j++]=' ';
                            for (n=0; n<(int)strlen(cursorFetchList[ncur]);n++)
              {
                puCodeDest[j++]=cursorFetchList[ncur][n];
              }
              puCodeDest[j++]='\n';
                            for (n=0; n<(int)strlen(cursorFromClause[ncur]);n++)
              {
                puCodeDest[j++]=cursorFromClause[ncur][n];
              }
              puCodeDest[j++]=';';
              puCodeDest[j++]='\n';
              // MD - 26/10/2001
              strncat(puCodeDest,"EXCEPTION\nWHEN OTHERS THEN null;\n",33);
              strncat(puCodeDest,"END;\n",5);
              if (cursorCommented[ncur][0] == '*')
              {
                strncat(puCodeDest,"*/\n",3);
                j += 41;
              }
              else
              {
                j += 38;
              }
              break;
            }
            else
            {
              i++;
            }
          }
        }
        else
        {
          puCodeDest[j++]=puCode[i];
        }
      }
      for (p=0; p<NBCUR; p++)
      {
        cursorFetchFound[p][0]='\0';
      }
      puCodeDest[j] = '\0';
      lg_puCodeDest = strlen(puCodeDest);
          if ((strcasestr( puCodeDest, "%NOTFOUND" ) != NULL) ||
            (strcasestr( puCodeDest, "%FOUND" ) != NULL))
          {
            for(i=0,ind=-1;i<lg_puCodeDest;i++)
            {
          
              if (puCodeDest[i] == '\0')
                break;
              if ((!strncasecmp(&puCodeDest[i],"%NOTFOUND",strlen("%NOTFOUND"))) ||
                (!strncasecmp(&puCodeDest[i],"%FOUND",strlen("%FOUND"))))
              {
                for (l=i-1,m=0; l>=0; l--)
                {
                  if ((puCodeDest[l] == ' ') || (puCodeDest[l] == '('))
                  {
                    for (n=0; n<m-1; n++)
                      ind--;
                    if (!strncasecmp(&puCodeDest[i],"%NOTFOUND",strlen("%NOTFOUND")))
                    {
                      puCodeFinal[ind++] = 'S';
                      puCodeFinal[ind++] = 'Q';
                      puCodeFinal[ind++] = 'L';
                      puCodeFinal[ind++] = '%';
                      puCodeFinal[ind++] = 'N';
                      puCodeFinal[ind++] = 'O';
                      puCodeFinal[ind++] = 'T';
                      puCodeFinal[ind++] = 'F';
                      puCodeFinal[ind++] = 'O';
                      puCodeFinal[ind++] = 'U';
                      puCodeFinal[ind++] = 'N';
                      puCodeFinal[ind] = 'D';
                      i += strlen("%NOTFOUND") - 1 ;
                    }
                    else if (!strncasecmp(&puCodeDest[i],"%FOUND",strlen("%FOUND")))
                    {
                      puCodeFinal[ind++] = 'S';
                      puCodeFinal[ind++] = 'Q';
                      puCodeFinal[ind++] = 'L';
                      puCodeFinal[ind++] = '%';
                      puCodeFinal[ind++] = 'F';
                      puCodeFinal[ind++] = 'O';
                      puCodeFinal[ind++] = 'U';
                      puCodeFinal[ind++] = 'N';
                      puCodeFinal[ind] = 'D';
                      i += strlen("%FOUND") - 1 ;
                    }
                    break;
                  }
                  else
                    m++;
                }
              }
              else
              {
                ind++;
                puCodeFinal[ind] = puCodeDest[i];
              }
            }
            puCodeFinal[++ind] = '\0';
          }
          else
            strncpy(puCodeFinal,puCodeDest,lg_puCodeDest);
    }
    /*
    free(fetchName);
    for (i=0; i<NBCUR; i++)
    {
      free(cursorFetchList[i]);
      free(cursorSelectList[i]);
      free(cursorFromClause[i]);
      free(cursorName[i]);
    }
    */
  }
  else
    strcpy(puCodeFinal,puCode);
 
  d2fpgus_pgu_txt(pd2fctx, pd2fpgu, puCodeFinal);

  // Now change the trigger code to call the program unit...
  strcpy(triggerCode, progUnitName);
  strcat(triggerCode, ";");
  d2ftrgs_trg_txt(pd2fctx, pd2ftrg, triggerCode);

  free(puCode);
  //free(puCodeDest);
  free(puCodeFinal);
    //free(puCode);
  return (SUCCESS);
}

///////////////////////////////////////////////////////////////////////////////////////
int enableComponents(char *componentFlag)
{
  if (strchr(componentFlag, 'F') || strchr(componentFlag, 'f'))
    FORM = TRUE;
  if (strchr(componentFlag, 'B') || strchr(componentFlag, 'b'))
    BLOCK = TRUE;
  if (strchr(componentFlag, 'I') || strchr(componentFlag, 'i'))
    ITEM = TRUE;
  if (strchr(componentFlag, 'P') || strchr(componentFlag, 'p'))
    PROPERTYCLASS = TRUE;

  return(SUCCESS);
}

///////////////////////////////////////////////////////////////////////////////////////
int IsV2Style(d2fctx *pd2fctx,d2ftrg *pd2ftrg)
{
/*
** Trigger Style (D2FP_TRG_STY)
** [TS]
#define D2FC_TRST_PLSQL            0
#define D2FC_TRST_V2               1
*/

    unsigned int style;

    d2ftrgg_trg_sty(pd2fctx, pd2ftrg, &style);

  if (style == D2FC_TRST_PLSQL)
  {
    return (FALSE); // NO it is NOT a V2 style trigger
  }
  else
  {
    fprintf(output,"Found V2 style Trigger, ignoring trigger...\n", style);
    return (TRUE);
  }
}
/////////////////////////////////////////////////////////////////////
int detectSelect(char *triggerCode)
{
  // MD 02-NOV-2001

   if (  (strcasestr(triggerCode, "SELECT")!=NULL) &&
         (strcasestr(triggerCode, "FROM"  )!=NULL) )
   {
        return (TRUE);
    }
    else
    {
        return (FALSE);
    }
}
/////////////////////////////////////////////////////////////////////
int detectCursor(char *triggerCode)
{
  // MD 02-NOV-2001
    if ( (strcasestr(triggerCode, "CURSOR")!=NULL) &&
     (strcasestr(triggerCode, "SELECT")!=NULL) &&
         (strcasestr(triggerCode, "FROM"  )!=NULL) )
    {
        return (TRUE);
    }
    else
    {
        return (FALSE);
    }
}
/*      With count limit
**      ----------------
*/
int strncasecmp (char * a, char * b, int n)
{
        char *p =a;
        char *q =b;
        int diff;

        for(p=a, q=b;; p++, q++) {
            if (p == a+n)
        return 0;     /*   Match up to n characters */
            if (!(*p && *q))
        return *p - *q;
            diff = tolower(*p) - tolower(*q);
            if (diff)
        return diff;
        }
        /*NOTREACHED*/
}
/*
** strcasestr(s1,s2) -- like strstr(s1,s2) but case-insensitive.
*/
char * strcasestr (char * s1, char * s2)
{
    char * ptr = s1;

    if (!s1 || !s2 || !*s2) return s1;

    while (*ptr) {
        if (toupper(*ptr) == toupper(*s2)) {
            char * cur1 = ptr + 1;
            char * cur2 = s2 + 1;
            while (*cur1 && *cur2 && toupper(*cur1) == toupper(*cur2)) {
                cur1++;
                cur2++;
            }
            if (!*cur2) return ptr;
        }
        ptr++;
    }
    return NULL;
}