[NEWSboard IBMi Forum]
Seite 1 von 2 1 2 Letzte
  1. #1
    Registriert seit
    Apr 2012
    Beiträge
    360

    Trigger Sql-updates

    Hallo,

    ich habe mir im Internet folgendes Pgm gefunden, was das aufrufende Programm ermittelt

    Code:
    Which program fired the trigger  
    * Prototype for the AppPgmName proceduree                     
    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 )         
                                                                  
     * Prototypess                                                 
    D SndMsg          PR                  ExtPgm( 'QMHSNDPM')      
    D  MsgId                         7    Const                    
    D  QlMsgfName                   20    Const                    
    D  MsgDta                      256    Const                    
    D                                     Options( *VarSize )      
    D  LenMsgDta                    10I 0 Const                    
    D  MsgType                      10    Const                    
    D  ClStkEntry                   10    Const                    
    D  ClStkCounter                 10I 0 Const                    
    D  MsgKey                        4                             
    D  ApiErr                      272                             
                                                                  
    D RcvMsg          PR                  ExtPgm( 'QMHRCVPM' )     
    D  MsgInf                      120                        
    D  LenMsgIfn                    10I 0 Const               
    D  FmtName                       8    Const               
    D  ClStkEntry                   10    Const               
    D  ClStkCounter                 10I 0 Const               
    D  MsgType                      10    Const               
    D  MsgKey                        4    Const               
    D  WaitTime                     10I 0 Const               
    D  MsgAct                       10    Const               
    D  ApiErr                      272                        
                                                             
     * Local data                                             
    D MsgKey          S              4                        
                                                             
    D ApiErr          DS                                      
    D  AeBytesProv                  10I 0 Inz( 272 )          
    D  AeBytesAvl                   10I 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 CurrPgmName     S             10                                             
    D PgmNameChanges  S              1P 0                                          
    D ClStkCounter    S             10I 0                                          
    D*                                                                             
     * Send a dummy message to the trigger                                         
    C                   CallP     SndMsg( 'CPF9898': 'QCPFMSG   QSYS':             
    C                                     ' ':       1:                            
    C                                     '*INFO':   '*PGMBDY':                    
    C                                     1:         MsgKey:                       
    C                                     ApiErr                         )         
    C*                                                                             
     * 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*                                                                             
    C                   Eval      TrgPgmName = MiPgmName                           
    C*                                                                             
     * Keep going backward in the call stack until the program name changes        
    * twice. The second change to the program name will be the name of         
     * the application which caused the trigger to fire.                        
    C*                                                                          
    C                   Eval      CurrPgmName = TrgPgmName                      
    C                   Eval      PgmNameChanges = *Zero                        
    C                   Eval      ClStkCounter = 2                              
    C                   DoU       PgmNameChanges = 2                            
    C*                                                                          
    C                   CallP     SndMsg( 'CPF9898':     'QCPFMSG   QSYS':      
    C                                     ' ':           1:                     
    C                                     '*INFO':       '*PGMBDY':             
    C                                     ClStkCounter:  MsgKey:                
    C                                     ApiErr                         )      
    C*                                                                          
    C                   CallP     RcvMsg( MsgInf:      %Size( MsgInf ):         
    C                                     'RCVM0200':  '*':                     
    C                                     *Zero:       '*INFO':                 
    C                                     MsgKey:      0:                       
    C                                     '*REMOVE':   ApiErr          )        
    C*                                                                          
    C                   If        MiPgmName <> CurrPgmName                      
    C                   Eval      CurrPgmName    = MiPgmName                    
    C                   Eval      PgmNameChanges = PgmNameChanges + 1           
    C                   Else                                                    
    C                   Eval      ClStkCounter = ClStkCounter + 1            
    C                   EndIf                                                
    C*                                                                       
    C                   EndDo                                                
    C*                                                                       
    C                   Return    CurrPgmName                                
    C*                                                                       
    P AppPgmName      E
    Das klappt ja auch toll, aber falls updates über Sql-Statements erfolgen wird mir immer QSQRUN3 zurückgeliefert.
    Click image for larger version. 

Name:	Neue Bitmap.jpg 
Views:	19 
Size:	29,1 KB 
ID:	275

    Welche Möglichkeiten würden bestehen um trotzdem das aufrunfende Programm zu ermitteln?

    Mir fällt da nur die Datenstruktur UDS ein.

    Code:
    D MyPGM          UDS
    Dank im Voraus für eure Hilfe.

    Tarki
    Angehängte Grafiken Angehängte Grafiken

  2. #2
    Registriert seit
    Feb 2001
    Beiträge
    20.238
    2 Möglichkeiten:
    a) solange rückwärts im Callstack senden, bis das 1. Programm nicht mit "Q" anfängt.
    b) in der DS MsgInf wird auch die Lib übergeben, also prüfen bis Lib <> QSYS

    Dabei würde ich allerdings spezielle Programmnamen wie von STRSQL spezifisch behandeln.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  3. #3
    Registriert seit
    Feb 2001
    Beiträge
    20.238
    Ich mache das (seit V5R2) so:

    Code:
     * --------------------------------------------------------
     * API-Definitionen CALLSTACK                              
     * --------------------------------------------------------
    DGetStack         pr                  extpgm('QWVRCSTK')   
    d                             2000                         
    d                               10I 0 const                
    d                                8    const                
    d                               56                         
    d                                8    const                
    d                               16                         
                                                              
    dStackInfo        ds          2000                          
    d ByteAvail                     10I 0 inz(%size(StackInfo)) 
    d ByteReturn                    10I 0                       
    d Entries                       10I 0                       
    d Offset                        10I 0                       
    d Count                         10I 0                       
                                                                
    dApiErr           ds                                        
    d ErrAvail                      10I 0 inz(16)               
    d ErrReturn                     10I 0                       
    d ErrReserv                      1                          
    d ErrMsg                         7                          
                                                                
    dStackID          ds                                        
    d IdInfo                        26    inz('*')              
    d IdInt                         16    inz                   
    d IdRes                          2    inz(*loval)           
    d IdThread                      10I 0 inz(1)                
    d IdThId                         8    inz(*loval)           
                                                               
    dStackPtr         s               *                   
    dStackEntry       ds                  based(StackPtr) 
    d EntryLen                      10I 0                 
    d EntryDispSt                   10I 0                 
    d EntryStmtNo                   10I 0                 
    d EntryDispPr                   10I 0                 
    d EntryProcLen                  10I 0                 
    d EntryReqLvl                   10I 0                 
    d EntryPgm                      10                    
    d EntryLib                      10                    
                                                          
    d StackAct        s             10I 0                 
    d FirstQ          s              1                    
                                                         
    c/free
             callp GetStack(StackInfo:%size(StackInfo):'CSTK0100' 
                            :StackId:'JIDF0100':ApiErr);          
             if ErrReturn = *zero;                                
                StackPtr = %addr(StackInfo) + Offset;             
                FirstQ = *off;                                    
                for StackAct = 0 to Entries - 1;                  
                    if FirstQ = *off;                             
                       if %subst(EntryPgm:1:1) = 'Q';             
                          FirstQ = *on;                           
                       endif;                                     
                    else;                                         
                       if %subst(EntryPgm:1:1) <> 'Q'             
                       or EntryLib <> 'QSYS';                     
                          LEPROG = EntryPgm;   // gefundenes Programm
                          LEPLIB = EntryLib;       // in Lib
                          leave;                                  
                       endif;                                     
                    endif;                                        
                    StackPtr += EntryLen;                         
                endfor;                                          
     /endfree
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  4. #4
    Registriert seit
    Aug 2001
    Beiträge
    2.873
    Eigentlich ist das ziemlich einfach. Das eigentliche Trigger-Programm wird durch eines der beiden QDBPUT (für Input-Trigger) oder QDBUDR (für Undate/Delete/Read-Trigger) aufgerufen. Damit muss man nur das Programm, das im Callstack vor dem entsprechenden Aktivierungsprogramm liegt ermitteln.

    Birgitta
    Birgitta Hauser

    Anwendungsmodernisierung, Beratung, Schulungen, Programmierung im Bereich RPG, SQL und Datenbank
    IBM Champion seit 2020 - 4. Jahr in Folge
    Birgitta Hauser - Modernization - Education - Consulting on IBM i

  5. #5
    Registriert seit
    Feb 2001
    Beiträge
    20.238
    Das ist leider nicht ganz richtig.
    Bei mir liegt bei COBOL zwischen dem QDBUDR und dem Auslöser noch das QLNRFIDX.
    Ich muss also weiter gehen.
    Je nach Programmsprache können da schon Unterschiede im Callstack durch Runtime-Programme auftreten.
    "Q"-Programme ist auch nicht eindeutig, da durch Programmerstellung und Verschiebung in QRPLOBJ das Objekt dort auch mit "Q" anfängt, deshalb ist hier die Lib auch wieder entscheidend.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  6. #6
    Registriert seit
    Apr 2012
    Beiträge
    360
    Danke Herr Fürchau, hat toll geklappt.

  7. #7
    Registriert seit
    Apr 2012
    Beiträge
    360
    Zitat Zitat von B.Hauser Beitrag anzeigen
    Eigentlich ist das ziemlich einfach. Das eigentliche Trigger-Programm wird durch eines der beiden QDBPUT (für Input-Trigger) oder QDBUDR (für Undate/Delete/Read-Trigger) aufgerufen. Damit muss man nur das Programm, das im Callstack vor dem entsprechenden Aktivierungsprogramm liegt ermitteln.

    Birgitta
    Hallo Birgitta,

    im Internet hast du folgendes zu QDBPUT/QDBUDR gepostet.
    Code:
    /*****************************************************************/   
    /*    Object. . . . . . . . .  : PRVPGM                          */ 
    /*    Funkcion. . . . . . . .  : Retrieve Caller Programm        */   
    /*                               from Call Stack                 */    
    /*    Parameter . . . . . . .  : CALLER   10 A                   */    
    /*                               CALLED   10 A                   */    
    /*    Author  . . . . . . . .  : B.Hauser                        */    
    /*****************************************************************/ 
                PGM        PARM(&CALLER           +           
                                &CALLED)   
    /* ---------------------------------------------------------------*/  
                DCL        VAR(&CALLER) TYPE(*CHAR) LEN(10)         
                DCL        VAR(&CALLED) TYPE(*CHAR) LEN(10)        
                DCL        VAR(&MSGKEY)   TYPE(*CHAR) LEN(4)  
                DCL        VAR(&SENDER)   TYPE(*CHAR) LEN(80)
    /* ---------------------------------------------------------------*/ 
                SNDPGMMSG  MSG('TEST')                                  +       
                           TOPGMQ(*PRV (&CALLED))                       +            
                           MSGTYPE(*RQS)                                +        
                           KEYVAR(&MSGKEY)       
    
               RCVMSG     PGMQ(*PRV (&CALLED))                         + 
                          MSGKEY(&MSGKEY)                              +      
                          SENDER(&SENDER)    
    
               CHGVAR     VAR(&CALLER) VALUE(%SST(&SENDER 56 10))  
    ENDE:     ENDPGM
    Mein Problem ist das ich ermitteln muss woher das Update(QDBUDR) kommt.
    Habe ein PF-File wo als "Triggerprogramm" ein Cl hinterlegt(JRN050CL) ist, das wiederum andere CL-aufruft.
    Das dritte CL ruft ein RPG-Programm auf und schreibt im Endeffekt den geänderten Satz.

    Wie ermittle ich nach deiner Methode den Aufruf?
    Muss ich im RPG-Programm nach den Wert 'QDBUDR' abfragen und dann das CL-aufrufen.
    Wie müsste der Aufruf des CL in einem Rpg-Pgm aussehen?

    lg und Dank im Voraus

  8. #8
    Registriert seit
    Aug 2001
    Beiträge
    2.873
    Dein aufgerufenes Programm ist QDBUDR und das rufende Programm must Du ermitteln.
    Also übergibst Du im Parameter CALLED QDBUDR und bekommts in CALLED das Programm, das den Trigger aktiviert hat.

    Birgitta
    Birgitta Hauser

    Anwendungsmodernisierung, Beratung, Schulungen, Programmierung im Bereich RPG, SQL und Datenbank
    IBM Champion seit 2020 - 4. Jahr in Folge
    Birgitta Hauser - Modernization - Education - Consulting on IBM i

  9. #9
    Registriert seit
    Jun 2001
    Beiträge
    1.975
    Wir brauchen diese Funktion auch ab und zu.
    Dafür haben wir einen Trigger, (der nur angehängt wird wenn wir das brauchen), der mit dem Dateinamen in einer Datei nachsieht ob er protokollieren soll. Wenn ja schreibt er den gesammten Pgm Stack und einige zus. Infos (Datum Zeit, User, ...) in eine Datei mit 30 Programm-Namen Feldern.
    Häufig ist nämlich nicht nur das Pgm, sondern auch der Aufruf von Interesse.

    Allerdings haben bei uns alle Dateien einer allg. Trigger, der den eigentlichen Trigger aus einer Datei ausliest und per Call ruft.
    Das hat den Vorteil, das wir zu jeder Zeit Trigger "runter" / "rauf" schalten können.
    Das Notwendige steht über dem technisch machbaren.
    (klingt komisch, funktioniert aber!)

  10. #10
    Registriert seit
    Apr 2012
    Beiträge
    360
    Habe es jetzt umgesetzt und bekomme aber einen Fehler.

    Mein Rpg-Code
    Code:
    D PRVPGM          PR                  EXTPGM('PRVPGM')     
    D  CALLER_                      10A   Options( *Omit )     
    D  CALLED_                      10A   Options( *Omit )     
    D*                                                         
    D  CALLER_ID      S             10A                        
    D  CALLED_ID      S             10A                        
          :
          :
    IF CHGPGM = 'QDBUDR';                              
      CALLER_ID = 'QDBUDR';                            
      CALLED_ID = *BLANKS;                             
      CALLP(E) PRVPGM(CALLER_ID : CALLED_ID);          
      IF CALLED_ID <> *BLANKS AND %ERROR = *OFF;       
        CHGPGM = CALLED_ID;                            
      ELSE;                                            
        IF %ERROR;                                     
          CHGPGM = 'ERR:PRVPGM';                       
        ENDIF;                                         
      ENDIF;                                           
    ENDIF;

    Joblog
    Code:
                                  Modulquelle anzeigen                              
                                                                                    
     Programm:   PRVPGM         Bibliothek:   SRCTST         Modul:   PRVPGM        
         14               DCL        VAR(&SENDER)   TYPE(*CHAR) LEN(80)             
         15  /* ---------------------------------------------------------------*/   
         16               SNDPGMMSG  MSG('TEST') TOPGMQ(*PRV (&CALLED)) MSGTYPE(*RQ 
         17                                                                         
         18               RCVMSG     PGMQ(*PRV (&CALLED)) MSGKEY(&MSGKEY) SENDER(&S 
         19                                                                         
         20               CHGVAR     VAR(&CALLER) VALUE(%SST(&SENDER 56 10))        
         21                                                                         
         22   ENDE:       ENDPGM                                                    
                                                                                   
     
     
                            Weitere Nachrichteninformationen                        
                                                                                   
     Nachrichten-ID . . . . :   CPA0702       Bewertung  . . . . . . :   99         
     Nachrichtenart . . . . :   Anfrage                                             
     Sendedatum . . . . . . :   17.08.10      Sendezeit  . . . . . . :   11:12:50   
                                                                                   
     Nachricht . . . :   (C D I R) CPF2469 von Prozedur PRVPGM empfangen.           
     Ursache  . . . . :  Die ILE CL-Prozedur PRVPGM in Modul PRVPGM in Programm     
       PRVPGM in Bibliothek SRCTST stellte einen Fehler bei Anweisungsnummer        
       0000000116 fest. Der Nachrichtentext für CPF2469 ist: Fehler aufgetreten     
       beim Senden der Nachricht .  Die Taste F10 (falls verfügbar) oder den Befehl 
       DSPJOBLOG (Jobprotokoll anzeigen) verwenden, um die Nachrichten im           
       Jobprotokoll aufzulisten und eine ausführlichere Beschreibung der            
       Fehlerursache zu erhalten. Kann das Problem trotzdem nicht gelöst werden,    
       den technischen Dienst verständigen.                                         
     Fehlerbeseitigung:  Diese Abfragenachricht kann vermieden werden, indem die    
       Prozedur geändert wird. Nachrichten auf den Fehler hin überwachen (Befehl    
       MONMSG) und den Fehler in der Prozedur beheben. Um fortzufahren, einen       
                                                                       Weitere ...  
     Eingabetaste --> Weiter                                                        
     
       Öffnen von Teildatei ZPG001P in SEQONLY(*NO) geändert.               
       Abfrageoptionsdatei kann nicht abgerufen werden.                     
       Aufrufstapeleintrag nicht gefunden.                                  
       Fehler aufgetreten beim Senden der Nachricht .                       
       Funktionsprüfung. CPF2469 nicht überwacht durch PRVPGM bei Anweisung 
         0000000116, Instruktion X'0000'.                                   
       (C D I R) CPF2469 von Prozedur PRVPGM empfangen.                     
     ? I                                                                    
       Teildatei oder Kennsatz in Ausgangsdatei nicht gefunden oder         
         zurückgestellt.                                                    
       Wegen eines Fehlers Kopierbefehl beendet.                            
       Abfrageoptionsdatei kann nicht abgerufen werden.                     
       Abfrageoptionsdatei kann nicht abgerufen werden.                     
       1 Sätze aus Teildatei QDEFAULT kopiert.
    Was habe ich falsch gemacht?
    Feld CHGPGM wird über ein Srv-Pgm befüllt(Stackaufruf).

  11. #11
    Registriert seit
    Feb 2001
    Beiträge
    20.238
    Halte den Prozess mal auf dem SNDPGMMSG an und schaue dir die CALL-Stack mal genau an.
    Wenn das Programm im Stack nicht gefunden wird, gibts was auf die Finger.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  12. #12
    Registriert seit
    Apr 2012
    Beiträge
    360
    Aufrufstappel ist:
    Code:
    Art   Programm                 Anweisung         Prozedur         
          QCMD       QSYS                     /04FA                   
          ADDLIBLE   TSTPGM        2100       /0034                   
          QUOCPP     QPDA                     /07A0                   
          QUOMAIN    QPDA                     /011E                   
       1  QUOCMD     QSYS                     /01EA                   
          MNU01C     TSTPGM        6900       /008F                   
          MNU01R     T_TSTOBJ                        _QRNP_PEP_MNU01R 
          MNU01R     T_TSTOBJ      457               MNU01R           
          TPGM03     T_TSTOBJ                        _QRNP_PEP_TPGM03 
          TPGM03     T_TSTOBJ      2495              TPGM03           
          QRNXIO     QSYS          49                _QRNX_DB_UPDATE  
          QDBUDR     QSYS                     /0853
    Update wurde vom Testprogramm TPGM03 gemacht.

Similar Threads

  1. Grundkonzept Trigger
    By froehlich in forum IBM i Hauptforum
    Antworten: 2
    Letzter Beitrag: 06-02-03, 14:37
  2. Trigger mit Servicepgm
    By Robi in forum IBM i Hauptforum
    Antworten: 1
    Letzter Beitrag: 28-05-02, 16:45
  3. Trigger ab 5.1
    By lorenzen in forum IBM i Hauptforum
    Antworten: 2
    Letzter Beitrag: 11-01-02, 13:49
  4. Trigger Programme
    By Liebhoff in forum IBM i Hauptforum
    Antworten: 3
    Letzter Beitrag: 20-11-01, 19:52
  5. Trigger / ILE RPG
    By Frank Pusch in forum IBM i Hauptforum
    Antworten: 3
    Letzter Beitrag: 17-05-01, 09:34

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • You may not post attachments
  • You may not edit your posts
  •