Thank You--
Richard A. Wilson
Alchemy Systems, Inc.
Rick Wilson wrote in message
<4PdQ1.3928$Xt4.22...@news2.jacksonville.net>...
Thanks for resonding.
Rick Wilson
In article <%TeQ1.1267$3w2.22...@news.rdc1.ne.home.com>, "Tim"
C Eval PgmName = AppPgmName( *Omit )
Here it is...
* Prototype for the AppPgmName procedure
D AppPgmName PR 10
D DummyPrm 1 Options( *Omit )
* Procedure to return the name of the application
* program which fired the trigger
P AppPgmName B
D AppPgmName PI 10
D DummyPrm 1 Options( *Omit )
* Prototypes
D SndMsg PR ExtPgm( 'QMHSNDPM' )
D MsgId 7 Const
D QlMsgfName 20 Const
D MsgDta 256 Const
D Options( *VarSize )
D LenMsgDta 9B 0 Const
D MsgType 10 Const
D ClStkEntry 10 Const
D ClStkCounter 9B 0 Const
D MsgKey 4
D ApiErr 272
D RcvMsg PR ExtPgm( 'QMHRCVPM' )
D MsgInf 120
D LenMsgIfn 9B 0 Const
D FmtName 8 Const
D ClStkEntry 10 Const
D ClStkCounter 9B 0 Const
D MsgType 10 Const
D MsgKey 4 Const
D WaitTime 9B 0 Const
D MsgAct 10 Const
D ApiErr 272
* Local data
D MsgKey S 4
D ApiErr DS
D AeBytesProv 9B 0 Inz( 272 )
D AeBytesAvl 9B 0
D AeMsgId 7
D 1
D AeMsgDta 256
D MsgInf DS
D MiBytesRetd 1 4B 0
D MiBytesAvl 5 8B 0 Inz( 120 )
D MiPgmName 111 120
* Send a dummy message to the application
C CallP SndMsg( 'CPF9898': 'QCPFMSG
QSYS':
Note, the above line wraps however it is just one big line in the
actual code.
C ' ': 1:
C '*INFO': '*PGMBDY':
C 2: MsgKey:
C ApiErr
* Receive the message back and pick up the program name
C CallP RcvMsg( MsgInf: %Size( MsgInf
)
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr
C Return MiPgmName
P AppPgmName E
Mike Cravitz
NEWS/400 Technical Editor
>You can do this in OPM RPG but I provided an
>RPG IV subprocedure which does it. The subprocedure must be in the
>same program but not necessarily the same module as the trigger. This
>means it won't work if you try to place it in a service program.
It is possible to make this into a service program with only a minor
change. Instead of going 2 above the *PGMBDY in the call stack, you
can go 1 entry above the DB routine which calls the trigger. This is
what I do for all of my trigger programs.
Unfortunately, the name is different for insert operations than it is
for update and delete operations. (QDBPUT vs QDBUDR) But we can
change your dummy parameter to the trigger event code from the trigger
buffer (ie, byte 31), so we know to which DB routine to send the
message. I took the liberty to repost a slight variation of your
program below, which can be compiled as a service program.
H NoMain
H Option( *SrcStmt : *NoDebugIO )
* Prototype for the AppPgmName procedure
D AppPgmName PR 10
D TrgEvent 1 Const
* Procedure to return the name of the application
* program which fired the trigger
P AppPgmName B Export
D AppPgmName PI 10
D TrgEvent 1 Const
D DbPgmName S 10
* Trigger event constants
D TE_INSERT C '1'
D TE_DELETE C '2'
D TE_UPDATE C '3'
D ApiErr DS
D AeBytesProv 9B 0 Inz( 272 )
D AeBytesAvl 9B 0
D AeMsgId 7
D 1
D AeMsgDta 256
D MsgInf DS
D MiBytesRetd 1 4B 0
D MiBytesAvl 5 8B 0 Inz( 120 )
D MiPgmName 111 120
C If TrgEvent = TE_INSERT
C Eval DbPgmName = 'QDBPUT'
C Else
C Eval DbPgmName = 'QDBUDR'
C Endif
* Send a dummy message to the application
C CallP SndMsg( 'CPF9898':
C 'QCPFMSG QSYS':
C ' ': 1:
C '*INFO': DbPgmName:
C 1: MsgKey:
C ApiErr )
* Receive the message back and pick up the program name
C CallP RcvMsg( MsgInf: %Size( MsgInf
):
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr )
C Return MiPgmName
P AppPgmName E
The above program can then be called similar to your original call,
except that field TrgEvent must be defined in the DS used for the
trigger program's first *entry parameter:
C Eval PgmName = AppPgmName( TrgEvent )
Agreed. But at least if it is a single service program, it is
relatively easy to change in the (hopefully unlikely) event it does
change via a PTF or release upgrade process. This is part of the
advantage of using a service program over a module bound to each
trigger program. (But even at that, I'd make sure it was in a
separate module to you only have to recreate one module and do a
CRTPGM on each affected program.)
Doug
Thanks to everyone that responded.
Rick
In article <3612a1d3...@www.newslink400.com>, dha...@isgroup.net
I'm going to try Mike's ILE subprocedure tomorrow. That looks like the way to
go now that I have had a chance to look at it.
Rick
In article <DsBQ1.3998$Xt4.22...@news2.jacksonville.net>,
>I just had another thought. If you want to avoid hardcoding the system
>trigger programs, all you have to do is call the procedure twice (I am
>speaking of the CL solution from tnt400.com here). The first time use the
>name of the actual trigger program. This will return QDBPUT/QDBUDR (or what
>ever IBM calls the program in the future) and then the second time with the
>program returned from the first call. Not terribly efficient, but effective.
This will work. There are a couple of scenarios where this would fail.
But the scenarios are absurd. Here they are.
1) If the CL program name is the same as either the trigger program's
name or the IBM database management program's name (QDBUDR).
2) If the trigger program name is the same as the IBM database
management program's name.
First of all, nobody is likely to name thier own program the same name
as an IBM program. Second of all, most folks insure that they don't
have two programs with the same name. Note, it is not a recursion
error to have two DIFFERENT programs with the same name. Anyway, with
the understanding that 1) and 2) are the only ways (I can think of
anyway) that this can fail, it seems like it should work.
Having said all that, I think it's better to have an RPG procedure do
this rather than a CL program. Triggers should not be calling CL
programs for efficiency reasons. Also triggers should not themselves
be CL programs. The reason is that CL programs can never end without
deactivating. You simply don't want the trigger to have to reactivate
every time you perform an I/O that fires the trigger. An RPG module
ends without deactivating by returning without setting on LR. With few
exceptions, triggers should end without deactivating. But this stuff
is quite doable with APIs. I'll post a solution later today.
********Procedure that must be included in the trigger programm******
H NoMain
* Prototype for the AppPgmName procedure
D AppPgmName PR 10
D DummyPrm 1 Options( *Omit )
* Procedure to return the name of the application
* program which fired the trigger
P AppPgmName B Export
D AppPgmName PI 10
D DummyPrm 1 Options( *Omit )
D ApiErr DS
D AeBytesProv 9B 0 Inz( 272 )
D AeBytesAvl 9B 0
D AeMsgId 7
D 1
D AeMsgDta 256
D MsgInf DS
D MiBytesRetd 1 4B 0
D MiBytesAvl 5 8B 0 Inz( 120 )
D MiPgmName 111 120
* Send a dummy message to the application
C CallP SndMsg( 'CPF9898': 'QCPFMSG
QSYS':
C ' ': 1:
C '*INFO': '*PGMBDY':
C 2: MsgKey:
C ApiErr )
* Receive the message back and pick up the program name
C CallP RcvMsg( MsgInf: %Size( MsgInf )
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr )
C Return MiPgmName
P AppPgmName E
******end of procedure that must be included in the trigger program***
******start of procedure that must be included in a service program***
H NoMain
* Prototype for the AppPgmName procedure
D AppPgmName PR 10
D DummyPrm 1 Options( *Omit )
* Procedure to return the name of the application
* program which fired the trigger
P AppPgmName B Export
D AppPgmName PI 10
D DummyPrm 1 Options( *Omit )
D ApiErr DS
D AeBytesProv 9B 0 Inz( 272 )
D AeBytesAvl 9B 0
D AeMsgId 7
D 1
D AeMsgDta 256
D MsgInf DS
D MiBytesRetd 1 4B 0
D MiBytesAvl 5 8B 0 Inz( 120 )
D MiPgmName 111 120
D TrgPgmName S 10
D DbMgtName S 10
* Send a dummy message to the trigger
C CallP SndMsg( 'CPF9898': 'QCPFMSG
QSYS':
C ' ': 1:
C '*INFO': '*PGMBDY':
C 1: MsgKey:
C ApiErr )
* Receive the message back and pick up the trigger program name
C CallP RcvMsg( MsgInf: %Size( MsgInf)
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr
C Eval TrgPgmName = MiPgmName
* Use similar technique to pick up the name of the IBM Database
* management routine
C CallP SndMsg( 'CPF9898': 'QCPFMSG
QSYS':
C ' ': 1:
C '*INFO': TrgPgmName:
C 1: MsgKey:
C ApiErr
C CallP RcvMsg( MsgInf: %Size( MsgInf)
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr )
C Eval DbMgtName = MiPgmName
* One more time to pick up the application program name
C CallP SndMsg( 'CPF9898': 'QCPFMSG
QSYS':
C ' ': 1:
C '*INFO': DbMgtName:
C 1: MsgKey:
C ApiErr )
C CallP RcvMsg( MsgInf: %Size( MsgInf)
C 'RCVM0200': '*':
C *Zero: '*INFO':
C MsgKey: 0:
C '*REMOVE': ApiErr )
C Return MiPgmName
******end of procedure that must be included as a service program***
Thanks again for the help.
Rick