Link to home
Start Free TrialLog in
Avatar of Theo Kouwenhoven
Theo KouwenhovenFlag for Netherlands

asked on

Trigger

Hi Experts,

I have to add a file trigger on *Insert and *update, *after that will store the program name that's performing the update. Where to get the program name from????

Regards,

Murph.
Avatar of daveslater
daveslater
Flag of United States of America image

Hi Murphey
this is proably the easiert way
https://www.experts-exchange.com/questions/20873205/COBOL-Get-Program-ID-Automatically.html
Dave

there are other AIP's available

I can publish some code that I use if u want

Dave
Avatar of Theo Kouwenhoven

ASKER

Hi Dave,

Normally I believe you directly, but I don't think that the *PRV will work.
  SNDPGMMSG  MSG('WHO CALLED ME?') TOPGMQ(*PRV (&PGM))
... wait I will test.....

No, Copied your source to a CL -> make CL the *After *update trigger
and changed a record with DFU.
No result.... After removing the MONMSG I got error:
      CPF2479 Call stack entry not found.

So An other Idea ???
ASKER CERTIFIED SOLUTION
Avatar of daveslater
daveslater
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
As I already described, It's eexcuted by a file trigger, so I don't have a calling program to refer to.
Avatar of Helixir
Helixir

I ususally add a field in my file to solve these problem, so my trigger can work with the Option that was called or a Username or Program name !! Because I think that Quser is the caller !!

Like Murphey, I dont think that there's a previous caller program to a trigger, well, there's a previous programm but it's not the prgram that Chnaged the file.

But if there's a way it's fantastic !!
Hi both
Have I got this wrong?
When I use a trigger I create an RPGLE program that accepts the 2 standard parms. It has a before and after immage.
I then use addpftrg to add the trigeer to the data base.
Then when a record is added, updated etc the trigger is evoked.
I have about 30 "trigger audit programs" currently running on my system that correctly populate the the program ID.

When a trigger is evoked is is evoked by a program that is performing database activity. All the CL is doing is getting the program that program.
This could be SQL, DFU, or any application program.

I will create quick demo later.

Dave
Then like I said it's fantastic !! ;)

I Tought about something , When I first tried to retreive program ID it was from a file I updated by DDM. and like, when you use DDM, it's Quser that take action on the file, it's why I was using a field with the Pogram ID, then from a system to another I could make follow the information.

Anyway, if a trigger couldn't retrieve Program ID how does Journal could ??

Thanks Dave to keep us on the good way !!
Sorry Dave,

What i already expected, the caller in your example is always: QDBUDR
But calling the second call with previous caller it gives me the right one

G R E A T

Thanks


Hi
just one word of warning - When using embeded SQL with-in an application program, the returned calling program is SQL and not the program name.

When I have a free half-day  will generate a fix.

Dave
When you organize your work on a AS/400 the right way.....
you have every day a free half-day ;)

Thanks for the quick answer!!

You might try calling this program from your Trigger program,
to obtain the program that fired the trigger:

 **********************************************************************
 * DATA STRUCTURES
 **********************************************************************
 *
 * SYSTEM API ERROR CODE
 *
D QUSEC           DS
D  QUSBPRV                1      4B 0
D  QUSBAVL                5      8B 0
D  QUSEI                  9     15
D  QUSERVED              16     16
 *
 * TYPE DEFINITION FOR THE RCVM0200 FORMAT
 *
D RCVM0200        DS           250
D  PROGRAM              111    120
 *
 **********************************************************************
 * STANDALONE FIELD DEFINITIONS
 **********************************************************************
 *
* PROGRAM MESSAGE PARAMETERS
*
D PM_MSGID        S              7    INZ(*BLANKS)
D PM_MSGF         S             20    INZ(*BLANKS)
D PM_MSGDTA       S              9    INZ('Caller ID')
*
D PM_LENGTH       S              9B 0
D PM_FORMAT       S              8    INZ('RCVM0200')
D PM_CSENTRY      S             10    INZ('*')
D PM_COUNTER      S              9B 0 INZ(6)
D PM_MTYPE        S             10    INZ('*INFO')
D PM_MKEY         S              4    INZ(*BLANKS)
D PM_WAIT         S              9B 0 INZ(0)
D PM_ACTION       S             10    INZ('*REMOVE')
*
**********************************************************************
* PARAMETER LISTS
**********************************************************************
*
* INPUT PARAMETERS
*
C     *ENTRY        PLIST
C                   PARM                    WPROGRAM         10
 *
 **********************************************************************
 * MAIN PROGRAM
 **********************************************************************
 *
 * SET ERROR CODE STRUCTURE NOT TO USE EXCEPTIONS
 *
C                   Z-ADD     16            QUSBPRV
 *
 * SET LENGTH OF MESSAGE DATA
 *
C                   Z-ADD     9             PM_LENGTH
 *
 * SEND PROGRAM MESSAGE
 *
C                   CALL      'QMHSNDPM'
C                   PARM                    PM_MSGID
C                   PARM                    PM_MSGF
C                   PARM                    PM_MSGDTA
C                   PARM                    PM_LENGTH
C                   PARM                    PM_MTYPE
C                   PARM                    PM_CSENTRY
C                   PARM                    PM_COUNTER
C                   PARM                    PM_MKEY
C                   PARM                    QUSEC
 *
 * CHECK FOR ERRORS
 *
C                   IF        QUSBAVL > 0
C                   EXSR      *PSSR
C                   ENDIF
 *
 * CLEAR RETURN DATA STRUCTURE
 *
C                   CLEAR                   RCVM0200
 *
 * SET LENGTH OF MESSAGE INFORMATION
 *
C                   Z-ADD     120           PM_LENGTH
 *
* RECEIVE PROGRAM MESSAGE
*
C                   CALL      'QMHRCVPM'
C                   PARM            RCVM0200
C                   PARM            PM_LENGTH
C                   PARM            PM_FORMAT
C                   PARM            PM_CSENTRY
C                   PARM            PM_COUNTER
C                   PARM            PM_MTYPE
C                   PARM            PM_MKEY
C                   PARM            PM_WAIT
C                   PARM            PM_ACTION
C                   PARM            QUSEC
*
* CHECK FOR ERRORS
*
C                   IF      QUSBAVL > 0
C                   EXSR      *PSSR
C                   ENDIF
*
C                   MOVE      PROGRAM      $PROGRAM
 *
C                   RETURN
 *
 **********************************************************************
 * *PSSR - ERROR HANDLING SUBROUTINE
 **********************************************************************
 *
C     *PSSR         BEGSR
 *
C                   RETURN
 *
C                   ENDSR

jhalbrook10,

Thanks, I think that this is more or less the same solution as David cameup with only the RPG-only version... Nice to know for the next time!!!
Another solution I've used in triggers, is using the Retrieve call stack API.
Here's an example:

      /Copy QSYSINC/QRPGLESRC,QWVRCSTK
      /Copy QSYSINC/QRPGLESRC,QWCATTR
      /Copy QSYSINC/QRPGLESRC,QUSEC


     D CStack          DS                  LikeDS(QWVK0100) Based(CStack_)
     D CStack_         S               *   Inz(%Addr(CStackDta))
     D CStackDta       S           4096

     D CStackEnt       DS                  LikeDS(QWVCSTKE) Based(CStackEnt_)
     D CStackEnt_      S               *   Inz(*Null)

     D JobIDDS         DS                  LikeDS(QWCF0100)

     D RtvCStack       PR                  ExtPgm(QWVRCSTK)
     D  RcvVar                     4096    Options(*VarSize)
     D  RcvVarLen                    10I 0 Const
     D  Format                        8A   Const
     D  JobID                        56A   Const Options(*VarSize)
     D  JobIDFormat                   8A   Const
     D  APIError                  32000    Options(*VarSize)

     D Idx             S             10I 0


     C                   Eval      JobIDDS.QWCJN02 = '*'
     C                   Eval      JobIDDS.QWCUN = *Blanks
     C                   Eval      JobIDDS.QWCJNBR00 = *Blanks
     C                   Eval      JobIDDS.QWCIJID = *Blanks
     C                   Eval      JobIDDS.QWCERVED06 = *ALLX'00'
     C                   Eval      JobIDDS.QWCTI00 = 1
     C                   Eval      JobIDDS.QWCTI01 = *ALLX'00'
     C
     C                   Callp     RtvCStack( CStackDta : %Size(CStackDta)
     C                                        : 'CSTK0100'
     C                                        : JobIDDS : 'JIDF0100'
     C                                        : QUSEC)

...

     C                   If        CStack.QWVERTN > 2
     C                   Eval      CStackEnt_ = CStack_ + CStack.QWVEO
     C                   For       Idx = 1 to 2
     C                   Eval      CStackEnt_ = CStackEnt_ + CStackEnt.QWVEL
     C                   Endfor
     C                   Endif

The FOR-loop finds the 2nd call stack entry below the current (because of the trigger's PEP), now the CStackEnt data structure contains info on the call stack entry that called the trigger. ex: CStackEnt.QWVPGMN contains the program name. You'll find a description of the DS in QSYSINC/QRPGLESRC,QWVRCSTK