Theo Kouwenhoven
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.
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.
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 ???
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
As I already described, It's eexcuted by a file trigger, so I don't have a calling program to refer to.
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 !!
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
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 !!
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 !!
ASKER
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
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
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
ASKER
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 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
ASKER
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!!!
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
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
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