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

    Veränderungsprotokoll über RCVJRNE

    Moin,

    kurze Beschreibung des Vorhabens:
    Über RCVJRNE wollen wir ein Exit-PGM an das Journal hängen.
    Wir wollen dadurch Änderungen an Datensätzen mitbekommen und eine Art Protokoll erstellen, sprich "Wann wurde der Datensatz angelegt", "Wann hat wer welche Veränderungen vorgenommen", "Wann wurde der Datensatz gelöscht".
    Das ganze für den "normalen" Benutzer über die Standard Journal-Funktion hinaus.
    Außerdem soll das für mehrere Dateien gelten und idealerweise wollen wir nicht für jede Datei ein eigenes Programm erstellen.

    Was ich bislang hinbekommen habe:
    (Besser wusste ich es nicht. Vorschläge wie man es besser macht höre ich gerne.)

    • Exit-PGM, welches die Journaldaten erhält.
    • Exit-PGM ruft Programm auf, welches über SQL eine Tabelle erstellt wie die Datei aus den Journaldaten, um die Dateifelder zu erhalten. (Die Datei erhält lvlchk *no wegen der nachfolgenden Programme)
    • Exit-PGM ruft Programm auf und übergibt Journaldaten. Daten werden über das aufgerufene Programm in die per SQL erstellte Tabelle geschrieben.
    • Exit-PGM ruft bei Update Programm auf, welche die Datensätze 1 (UB) und 2 (UP) aus der per SQL erstellten Tabelle ausliest, in Datenstrukturen (likerec der Tabelle) packt und die Datenstrukturen vergleicht. So weiß ich, ob überhaupt eine Veränderung stattgefunden hat.


    Jetzt zum Problem:
    Per SQL komme ich zwar, über syscolumns, an die Spaltennamen und die Anzahl der Spalten, aber mir fällt nichts ein wie ich diese Spaltennamen dann einzeln abfragen kann auf Veränderung.
    Eine Datenstruktur (likerec der Tabelle) wird zwar korrekt gefüllt, aber ich kann die einzelnen Felder der Datenstruktur nicht abfragen, da ich den Namen nicht weiß. Oder kann man die Felder auch über Nummern abfragen? Quasi anstatt Datenstruktur.Feldname1 Datenstruktur.Feldnummer1?
    Oder sonst Ideen wie ich weitermachen könnte?

    Gruß

  2. #2
    Registriert seit
    Feb 2001
    Beiträge
    20.696
    Da hilft nur ein bisschen Arbeit:
    Per SYSCOLUMNS kannst du dir zu den Namen die relative Position und Typen ja abfragen.
    Jetzt führst du nur eine Tabelle mit den Namen und der rel. Adresse in der DS.
    Dann kannst du per %subst(MyDs:Pos:Len) über den Namen extrahieren und verarbeiten.
    Gepackte Daten würde ich in eine HilfsDS packen:

    D NumDS ds
    D NumFld 31p 0

    d HelpDS DS
    d HelpNum 31p 0 inz
    d HelpX 15 overlay(HelpNum)

    evalr NumDs = HelpX + %subst(MyDs:Pos:Len)
    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
    Nov 2003
    Beiträge
    2.403
    Zitat Zitat von Ottersberg Beitrag anzeigen
    Wir wollen dadurch Änderungen an Datensätzen mitbekommen und eine Art Protokoll erstellen, sprich "Wann wurde der Datensatz angelegt", "Wann hat wer welche Veränderungen vorgenommen", "Wann wurde der Datensatz gelöscht".
    Sind für sowas Trigger denn nicht besser geeignet?

  4. #4
    Registriert seit
    Jun 2001
    Beiträge
    2.044
    Ich mach das anders ...
    ich ermittel die Start und Ende Position jedes Feldes aus der Datei.
    somit habe ich feldname, start und ende.
    mit einem srvpgm bekomme ich den geänderten Feldnamen und die 'bis' position
    Dann bilde ich einen String, Feldname: alter Inhalt : neuer inhalt, |
    bis 204 Spalten voll sind(nicht mehr reichen) 204 weil mehr der Drucker nicht kann und für bestimmte Dateien wird das gedruckt und abgezeichnet)
    dann druck und nächste Zeile
    alles in allem, 3-4 Programme für jede Dateien anwendbar.

    (verkürzte theoretische Darstellung, da unser Entw. System einige Besonderheiten mittbringt und ich z.B. die Spaltenfolge nicht via
    QADBILFI ermitteln brauche)

    Gruß
    Robi

    jetzt waren doch andere schneller ...
    @Pikachu
    Jain, wenn du es nicht je Datei machen willst ist das schon so ok.
    sonst hättest du je Datei einen trigger, der es entweder individuell macht oder die o.a logik durchführt. Das ist nicht immer das schnellste
    Last edited by Robi; 07-06-11 at 12:57. Grund: nachsatz
    Das Notwendige steht über dem technisch machbaren.
    (klingt komisch, funktioniert aber!)

  5. #5
    Registriert seit
    Apr 2008
    Beiträge
    83
    Zitat Zitat von Fuerchau Beitrag anzeigen
    Da hilft nur ein bisschen Arbeit:
    Per SYSCOLUMNS kannst du dir zu den Namen die relative Position und Typen ja abfragen.
    Jetzt führst du nur eine Tabelle mit den Namen und der rel. Adresse in der DS.
    Dann kannst du per %subst(MyDs:Pos:Len) über den Namen extrahieren und verarbeiten.
    Da kann dann auch die temporäre Tabelle im Look der Tabelle lt. Journaldaten entfallen.
    Das bin ich jetzt mal angegangen.

    Zitat Zitat von Robi Beitrag anzeigen
    Ich mach das anders ...
    ich ermittel die Start und Ende Position jedes Feldes aus der Datei.
    somit habe ich feldname, start und ende.
    mit einem srvpgm bekomme ich den geänderten Feldnamen und die 'bis' position
    Dann bilde ich einen String, Feldname: alter Inhalt : neuer inhalt, |
    bis 204 Spalten voll sind(nicht mehr reichen) 204 weil mehr der Drucker nicht kann und für bestimmte Dateien wird das gedruckt und abgezeichnet)
    dann druck und nächste Zeile
    alles in allem, 3-4 Programme für jede Dateien anwendbar.
    Klingt eigentlich wie der Ansatz von Fuerchau. Mich würde da noch interessieren, wie du Start und Ende Position ermittelst.
    Da fallen mir nur SYSCOLUMNS oder DSPFFD ein, wo ich das erste auf jeden Fall bevorzuge.

  6. #6
    Registriert seit
    Feb 2001
    Beiträge
    20.696
    SYSCOLUMNS ist das einfachste und auch schnellste, wenn man mit SQL arbeitet.
    DSPFFD mit Outfile ist auch einfach, wenn man keine API's verwenden möchte.
    API's sind auch schnell, wenn man sich damit auskennt (USRSPC-API's kommen noch hinzu).

    Wenn man sich mal per DSPFD die SYSCOLUMNS ansieht, bekommt man mit, welche Tabelle in der QSYS als Basis dient (QADB...).
    Früher habe ich mittels Direktzugriff die Informationen daraus gelesen, was aber zu stark releaseabhängig ist (Levelcheck-Error).
    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

  7. #7
    Registriert seit
    Mar 2002
    Beiträge
    5.365
    ... eigentlich ist nur relevant, wenn sich das Layout der Datei ändert, sprich: man müsste sich das cachen - führt unmittelbar dazu, dass man das Event verarbeitet, wenn sich die Datei ändert (kommt auch im Journal), was dann bedeutet, dass man sich auch ein statisches Programm generiert...


    D*B
    AS400 Freeware
    http://www.bender-dv.de
    Mit embedded SQL in RPG auf Datenbanken von ADABAS bis XBASE zugreifen
    http://sourceforge.net/projects/appserver4rpg/

  8. #8
    Registriert seit
    Jun 2001
    Beiträge
    2.044
    Klingt eigentlich wie der Ansatz von Fuerchau. Mich würde da noch interessieren, wie du Start und Ende Position ermittelst.
    Da fallen mir nur SYSCOLUMNS oder DSPFFD ein, wo ich das erste auf jeden Fall bevorzuge.
    ja, das ist ähnlich
    wir haben die START und ENDE Positionen in einer Datei in der wir nachschauen können. Das macht unser Entw. System automatisch.
    Bei einem Kunden, der 'herkömlich' arbeitet lesen wir die
    QADBILFI für die datei durch und merken alles in einer multi occur Tabelle. So haben wir nach und nach 30 Dateibeschreibungen im Zugriff.
    Robi
    Das Notwendige steht über dem technisch machbaren.
    (klingt komisch, funktioniert aber!)

  9. #9
    Registriert seit
    Apr 2008
    Beiträge
    83
    Zitat Zitat von Fuerchau Beitrag anzeigen
    Gepackte Daten würde ich in eine HilfsDS packen:

    D NumDS ds
    D NumFld 31p 0

    d HelpDS DS
    d HelpNum 31p 0 inz
    d HelpX 15 overlay(HelpNum)

    evalr NumDs = HelpX + %subst(MyDs:Pos:Len)
    Das verstehe ich noch nicht ganz.
    Als Beispiel krieg ich für ein DECIMAL-Feld (lt. syscolumns) mit length 6 und storage 4, was lt. DDS als 6P0 definiert ist, folgendes:
    PHP-Code:
    00000000000000000000000[]0019102 
    Das lässt sich nicht über %char() in einen Character umwandeln.

  10. #10
    Registriert seit
    Feb 2001
    Beiträge
    20.696
    Eben deswegen die HilfsDS.
    Gepackte Felder haben immer eine ungerade Anzahl Stellen, auch wenn man gerade Anzahl definiert hat.
    Definiere ich nun ein Hilfsfeld von 31p 0, kann ich per %subst das Feld aus der DS rechtsbündig in das Hilfsfeld übertragen, dabei muss ich natürlich nach vorne mit X'00' auffüllen:

    evalr NumDs = HelpX + %subst(MyDs:Pos:Len)

    Zur Ausgabe kann ich dann per %char(NumFld) den Wert aufbereiten.
    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

  11. #11
    Registriert seit
    Apr 2008
    Beiträge
    83
    Ja die hatte ich auch verwendet. Ich hatte sie nur falsch erweitert. Anstatt 63P0 mit 31 im overlay hatte ich 63P0 mit 32 im overlay.
    Jetzt gehts.

  12. #12
    Registriert seit
    Apr 2008
    Beiträge
    83
    Hier mal der Code, falls jemand es noch mal brauchen kann.
    ACHTUNG: Bislang keine Fehlerverarbeitung eingebaut!

    PHP-Code:

         H main
    (Main)
         
    H DFTACTGRP(*NO)

         
    DMain             PR                  extpgm('TESTJRN')
         
    DJournalDaten...
         
    D                                     likeds(DS_JournalDaten)
         
    DJournalCommunication...
         
    D                                     likeds(DS_JournalCommunication)

         
    DINT_DatenvergleichAenderung...
         
    D                 PR         32767A
         D                                     varying
         DINP_Bibliothek                 10A
         DINP_Tabelle                    10A

         DINT_PruefeZahl
    ...
         
    D                 PR            99A
         DINP_Zahl
    ...
         
    D                               63P 0 const
         
    DINP_Nachkommastellen...
         
    D                               10I 0

         DDS_JournalDaten
    ...
         
    D                 Ds                                                       DS bei ENTFMT(*Type2)
         
    D JOENTL                         5S 0                                      Entry Length
         D JOSEQN                        10S 0                                      Sequence Number
         D JOCODE                         1A                                        Journal Code
         D JOENTT                         2A                                        Entry Type
         D JODATE                         6A                                        Datum
         D JOTIME                         6S 0                                      Zeit
         D JOJOB                         10A                                        Jobname
         D JOUSER                        10A                                        Username
         D JONBR                          6S 0                                      Jobnummer
         D JOPGM                         10A                                        Programmname
         D JOOBJ                         10A                                        Objektname
         D JOLIB                         10A                                        Objektbibliothek
         D JOMBR                         10A                                        Member Name
         D JOCTRR                        10S 0                                      Count
    /RRN
         D JOFLAG                         1A                                        Flag
         D JOCCID                        10S 0                                      Commit Cycle ID
         D JOUSPF                        10A                                        User Profile
         D JOSYNM                         8A                                        System Name
         D JOINCDAT                       1A                                        Incomplete data
         D JOMINESD                       1A                                        Minimized Entry
         D JORES                         18A                                        Reserved
         D JODTA                      32767A                                        Entry
    -Specific Data

         DDS_JournalCommunication
    ...
         
    D                 Ds                                                       DS Für die Kommunik.
         
    D                                                                          mit dem RCVJRNE-Bef.
         
    D JOCTL                          1A
         D JOENTAVL                       1A
         D JOENTPAS                       1A

         PMain             B
         D                 PI
         DJournalDaten
    ...
         
    D                                     likeds(DS_JournalDaten)
         
    DJournalCommunication...
         
    D                                     likeds(DS_JournalCommunication)
          *-- 
    JOCTL journal control:  ------------------------------------------**
         
    DNoEnt            c                   '0'
         
    DSngEnt           c                   '1'
         
    DBlkEnt           c                   '2'
         
    DRcvChgEnd        c                   '3'
         
    DBegBlkMod        c                   '28'
         
    DEndRcvJrnE       c                   '9'
          
    *-- JOCODE journal code:
         
    DRcdTyp           c                   'R'

         
    DDS_Daten       E DS                  extname('TESTJRNETR')

         
    DChangedData      S         100000A   inz
         D                                     varying
          
    /free
           
    If JournalCommunication.JOCTL  SngEnt And
              
    JournalDaten.JOCODE RcdTyp;

               
    //Journaleintrags-Art verarbeiten
               
    Select;
               
    When JournalDaten.JOENTT 'UB';
                 
    //Daten lt. Journal in Datei abspeichern für späteren
                 //Vergleich mit UP-Satz
                 
    Daten JournalDaten.JODTA;
                 
    exec sql
                   insert into testjrnetr values
    (:DS_Daten);

               
    When JournalDaten.JOENTT 'UP';
                 
    //UP-Satz in Datei abspeichern für Vergleich
                 
    Daten JournalDaten.JODTA;
                 
    exec sql
                   insert into testjrnetr values
    (:DS_Daten);

                 
    //UB-Satz und UP-Satz miteinander vergleichen
                 
    ChangedData INT_DatenvergleichAenderung(
                   
    JournalDaten.JOLIB:JournalDaten.JOOBJ);
                 if 
    ChangedData <> *blanks;
                   
    //TODO
                 
    endif;
                 
    exec sql
                   delete from testjrnetr
    ;

               
    When JournalDaten.JOENTT 'PT'
               
    Or   JournalDaten.JOENTT 'PX';

               
    When JournalDaten.JOENTT 'DL';

               
    EndSl;

           endif;

           If %
    Shtdn;
             
    JOCTL EndRcvJrnE;
           Endif;
          /
    end-free
         P                 E

         PINT_DatenvergleichAenderung
    ...
         
    P                 B
         D                 PI         32767A
         D                                     varying
         DINP_Bibliothek                 10A
         DINP_Tabelle                    10A

         DETESTJRNETR    E DS                  extname
    ('TESTJRNETR')
         
    DDS_DatenUB       DS                  likeds(ETESTJRNETR)
         
    DDS_DatenUP       DS                  likeds(ETESTJRNETR)

         
    DAnzahlSpalten    S             10I 0 inz

          
    //DS für die Rückgabe aus syscolumns
         
    DSpalten          DS                  qualified
         D                                     dim
    (999)
         
    D Name                          10A
         D Typ                            8A
         D Laenge                        10I 0
         D Speicher                      10I 0
         D Genauigkeit                   10I 0
         D Nachkommastellen
    ...
         
    D                               10I 0

          
    //DS für Datenformat 'P' (Typ: DECIMAL)
         
    DPackedDS         DS
         D Packed                        63P 0 inz
         DPackedHelpDS     DS
         D PackedHelpNum                 63P 0 inz
         D PackedHelpX                   31    overlay
    (PackedHelpNum)

          
    //DS für Datenformat 'S' (Typ: NUMERIC)
         
    DZonedDS          DS
         D Zoned                         63S 0 inz
         DZonedHelpDS      DS
         D ZonedHelpNum                  63S 0 inz
         D ZonedHelpX                    62    overlay
    (ZonedHelpNum)

          
    //Verschiedene Zähler
         
    DPosition         S              5S 0 inz
         DPositionAdd      S              5S 0 inz
         Di                S             10I 0 inz

          
    //Felder für den Vergleich von UB- und UP-Sätzen
         
    DDatenUB          S          32767A   inz
         D                                     varying
         DDatenUP          S          32767A   inz
         D                                     varying

          
    //Rückgabewert
         
    DOut_Ergebnis     S          32767A   inz
         D                                     varying
          
    /free
           exec sql
             
    declare Datencursor Cursor for
               
    select daten
               from testjrnetr
    ;

           
    exec sql
             open Datencursor
    ;

           
    exec sql
             fetch next from Datencursor
               into 
    :DS_DatenUB ;

           
    exec sql
             fetch next from Datencursor
               into 
    :DS_DatenUP ;

           
    exec sql
             close Datencursor
    ;

           
    exec sql
             select count
    (*)
               
    into :AnzahlSpalten
               from syscolumns
               where system_table_name 
    = :INP_Tabelle
               
    and   system_table_schema = :INP_Bibliothek;

           
    exec sql
             
    declare Spaltencursor Cursor for
               
    select system_column_name,
                      
    data_type,
                      
    length,
                      
    storage,
                      case 
    when numeric_precision is null
                        then 0
                        
    else numeric_precision end,
                      case 
    when numeric_scale is null
                        then 0
                        
    else numeric_scale end
                 from syscolumns
                 where system_table_name 
    = :INP_Tabelle
                 
    and   system_table_schema = :INP_Bibliothek
                 order by ordinal_position
    ;

           
    exec sql
             open Spaltencursor
    ;

           
    exec sql
             fetch next from Spaltencursor
               
    for :AnzahlSpalten rows
               into 
    :Spalten;

           
    exec sql
             close Spaltencursor
    ;

           
    Position 1;
           for 
    1 to AnzahlSpalten;
             
    Select;
             
    //Variante Character
             
    When Spalten(i).Typ 'CHAR' or Spalten(i).Typ 'VARCHAR';
               
    PositionAdd Spalten(i).Speicher;
               
    DatenUB = %subst(DS_DatenUB :Position:Spalten(i).Laenge);
               
    DatenUP = %subst(DS_DatenUP :Position:Spalten(i).Laenge);
               if 
    DatenUB <> DatenUP;
                 if 
    DatenUB = *blanks;
                   
    DatenUB 'leer';
                 endif;
                 if 
    DatenUP = *blanks;
                   
    DatenUP 'leer';
                 endif;
                 
    OUT_Ergebnis = %trim(OUT_Ergebnis)
                              + 
    'Feld: '
                              
    + %trim(Spalten(i).Name)
                              + 
    ' ~ Alt: '
                              
    + %trim(DatenUB)
                              + 
    ' ~ Neu: '
                              
    + %trim(DatenUP)
                              + 
    ' |';
               endif;
             
    //Variante Numeric(Packed)
             
    When Spalten(i).Typ 'DECIMAL';
               
    PositionAdd Spalten(i).Speicher;
               
    evalr PackedDS =
                 
    PackedHelpX + %subst(DS_DatenUB :Position:Spalten(i).Speicher);
               
    DatenUB =
                 
    INT_PruefeZahl(%dec(Packed):Spalten(i).Nachkommastellen);

               
    evalr PackedDS =
                 
    PackedHelpX + %subst(DS_DatenUP :Position:Spalten(i).Speicher);
               
    DatenUP =
                 
    INT_PruefeZahl(%dec(Packed):Spalten(i).Nachkommastellen);

               if 
    DatenUB <> DatenUP;
                 
    OUT_Ergebnis = %trim(OUT_Ergebnis)
                              + 
    'Feld: '
                              
    + %trim(Spalten(i).Name)
                              + 
    ' ~ Alt: '
                              
    + %trim(DatenUB)
                              + 
    ' ~ Neu: '
                              
    + %trim(DatenUP)
                              + 
    ' |';
               endif;
             
    //Variante Numeric(Zoned)
             
    When Spalten(i).Typ 'NUMERIC';
               
    PositionAdd Spalten(i).Speicher;
               
    evalr ZonedDS =
                 
    ZonedHelpX + %subst(DS_DatenUB :Position:Spalten(i).Speicher);
               
    DatenUB =
                 
    INT_PruefeZahl(%dec(Zoned):Spalten(i).Nachkommastellen);

               
    evalr ZonedDS =
                 
    ZonedHelpX + %subst(DS_DatenUP :Position:Spalten(i).Speicher);
               
    DatenUP =
                 
    INT_PruefeZahl(%dec(Zoned):Spalten(i).Nachkommastellen);

               if 
    DatenUB <> DatenUP;
                 
    OUT_Ergebnis = %trim(OUT_Ergebnis)
                              + 
    'Feld: '
                              
    + %trim(Spalten(i).Name)
                              + 
    ' ~ Alt: '
                              
    + %trim(DatenUB)
                              + 
    ' ~ Neu: '
                              
    + %trim(DatenUP)
                              + 
    ' |';
               endif;
             
    //Varianten Date und Time
             
    When Spalten(i).Typ 'DATE'
               
    or Spalten(i).Typ 'TIME';
               
    PositionAdd Spalten(i).Speicher;
               
    DatenUB = %subst(DS_DatenUB :Position:Spalten(i).Laenge);
               
    DatenUP = %subst(DS_DatenUP :Position:Spalten(i).Laenge);
               if 
    DatenUB <> DatenUP;
                 
    OUT_Ergebnis = %trim(OUT_Ergebnis)
                              + 
    'Feld: '
                              
    + %trim(Spalten(i).Name)
                              + 
    ' ~ Alt: '
                              
    + %trim(DatenUB)
                              + 
    ' ~ Neu: '
                              
    + %trim(DatenUP)
                              + 
    ' |';
               endif;
             
    //Variante Timestamp
             
    When Spalten(i).Typ 'TIMESTMP';
               
    //Länge ist Fest 26. Lt. syscolums sind Länge und Speicher 10.
               
    PositionAdd 26;
               
    DatenUB = %subst(DS_DatenUB:Position:26);
               
    DatenUP = %subst(DS_DatenUP:Position:26);
               if 
    DatenUB <> DatenUP;
                 
    OUT_Ergebnis = %trim(OUT_Ergebnis)
                              + 
    'Feld: '
                              
    + %trim(Spalten(i).Name)
                              + 
    ' ~ Alt: '
                              
    + %trim(DatenUB)
                              + 
    ' ~ Neu: '
                              
    + %trim(DatenUP)
                              + 
    ' |';
               endif;
             
    Other;
               
    PositionAdd Spalten(i).Speicher;
               
    //ACHTUNG: Hier kann es evtl. zu Problemen kommen mit der Länge des Feldes
               //Ähnlich wie bei TIMESTMP.
               //TODO
             
    EndSl;
             
    Position Position PositionAdd;  
           endfor;
           return 
    OUT_Ergebnis;
          /
    end-free
         P                 E

         PINT_PruefeZahl   B
         D                 PI            99A
         DINP_Zahl
    ...
         
    D                               63P 0 const
         
    DINP_Nachkommastellen...
         
    D                               10I 0
         DOUT_Text         S             99A   inz
         Di                S             10I 0 inz
         DDivisor          S             63S 0 inz
    (1)
         
    DGanzzahl         S             63S 0 inz
         DKommazahl        S             63S 0 inz
          
    /free
           
    if INP_Nachkommastellen 0;
             
    OUT_Text = %char(INP_Zahl);
           else;
             for 
    1 to INP_Nachkommastellen;
               
    Divisor Divisor 10;
             endfor;
             
    Ganzzahl INP_Zahl/Divisor;
             
    Kommazahl INP_Zahl-(Ganzzahl*Divisor);
             
    OUT_Text = %char(Ganzzahl) + ','
                      
    + %char(Kommazahl);
           endif;
           return 
    OUT_Text;
          /
    end-free
         P                 E 

Similar Threads

  1. Journalling
    By RLurati in forum IBM i Hauptforum
    Antworten: 5
    Letzter Beitrag: 12-06-06, 08:16
  2. Journale
    By Frank Schuman in forum IBM i Hauptforum
    Antworten: 5
    Letzter Beitrag: 14-08-01, 19:29

Berechtigungen

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