Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Retrieving Triggering Program Name

1,307 views
Skip to first unread message

Rick Wilson

unread,
Sep 29, 1998, 3:00:00 AM9/29/98
to
While in a trigger program, does anyone know how to retrieve the name of the
program that performed the update/insert/delete that triggered the trigger
program? It does not seem to be in the trigger buffer. Maybe an API to
retrieve the call stack?

Thank You--
Richard A. Wilson
Alchemy Systems, Inc.

Tim

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
in the code examples at www.tnt400.com there is a sample program that
retrieves a program's caller


Rick Wilson wrote in message
<4PdQ1.3928$Xt4.22...@news2.jacksonville.net>...

Rick Wilson

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
I'm not sure if that will work or not since the trigger is not actually called
from the program that modified the file with the trigger program. I'll try it
and see what happens. There is also mention of an API there thant may help.

Thanks for resonding.

Rick Wilson

In article <%TeQ1.1267$3w2.22...@news.rdc1.ne.home.com>, "Tim"

Mike Cravitz

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
Odd coincidence. I just finished my first draft of an article which
talks in general about the subject of the application communicating
with a trigger. In the article I will have a sidebar discussing the
answer to your question. 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
works by sending and receiving a dummy message from the trigger to the
application. The name of the procedure is AppPgmName. You would invoke
it like this...

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

Douglas Handy

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
Mike,

>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 )


Mike Cravitz

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
Doug, I'm simply not comfortable with hard-coding the name of the IBM
routine that invokes the trigger. Unless it's documented to have that
name then IBM can change it from release to release (or even via a PTF
at the same release). I realize this is not likely, I just don't like
the idea of depending on this name. Having said all that I must
confess that after giving it much thought, I can't think of a more
robust solution than yours. Oh well.

Douglas Handy

unread,
Sep 30, 1998, 3:00:00 AM9/30/98
to
Mike,

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

Rick Wilson

unread,
Oct 1, 1998, 3:00:00 AM10/1/98
to
I used the simple little CL program from www.tnt400.com for retrieving the
calling program. It returned the triggering program name when I passed it
QDBPUT/QDBUDR in the &PGM parameter. I'm not happy about having to hard code
the AS/400 trigger program names but it works for now. It will have to be
something to watch for during version and PTF changes.

Thanks to everyone that responded.

Rick

In article <3612a1d3...@www.newslink400.com>, dha...@isgroup.net

Rick Wilson

unread,
Oct 1, 1998, 3:00:00 AM10/1/98
to
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.

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>,

Mike Cravitz

unread,
Oct 1, 1998, 3:00:00 AM10/1/98
to
Rick,

>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.

Mike Cravitz

unread,
Oct 1, 1998, 3:00:00 AM10/1/98
to
My earlier posts had a couple of syntax errors due to cut/paste
problems (at least that's what I want you to believe). I posted a
procedure that had to be included in the same program as the trigger.
I will repost (hopefully) without the syntax errors. Also I'm posting
a service program version that works without the trigger needing to
pass its own name. Both sets of code have been tested.

********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***

Rick Wilson

unread,
Oct 2, 1998, 3:00:00 AM10/2/98
to
I am going to use your RPG subprocedure. I started to code it today but ran
into problems with the cut & paste and I didn't have the time to figure out
what it was supposed to be.

As far as your resonse to my previous message, anyone who uses 'Q' as the
first letter of their CL or trigger program name is asking for trouble anyway
and probably deserves to have the problem!

Thanks again for the help.

Rick

0 new messages