[NEWSboard IBMi Forum]
  1. #1
    Registriert seit
    May 2014
    Beiträge
    5

    RPGLE-PGM crasht bei write in SQL-definierte Datei -- schreibt aber trotzdem!

    Hallo Forum,

    vielleicht könnt Ihr mir bei meinem Problem helfen:

    Ich schreibe in einem RPGLE-Programm in eine Datei, die ich per SQL-Create-Befehl erzeugt habe. Den Weg über SQL bin ich gegangen, weil ich lange Feldnamen haben wollte, die sich mit den Tags in einem XML-Dokument decken, das ich im Programm verarbeite. Dabei schreibe ich eine Datenstruktur, die wie das Satzformat definiert ist und die ich per Pointerakrobatik über die Datenstruktur mit den XML-Daten lege. Hier mal die (vermeintlich) relevanten Zeilen aus dem Quelltext:

    Code:
         FI3DGXARC  O    E             DISK
    
    (...)
    
         D dsDataQ         DS                  LikeDS(DATATRNQRS) XML-DS definiert in Copyfile
         D dsDSARC         DS                  LikeRec(I3DGXARR:*OUTPUT)
         D                                     based(§DATARS)
         D §DATARS         S               *   INZ      
    
    (...)
              xml-into dsDataQ
                %Xml($antwort :
                  'doc=string +
                   path=XML/DATA +
                   trim=all +
                   case=any +
                   allowmissing=yes +
                   allowextra=yes +
                   countprefix=Anz_ +
                  ');
    
    (...)
    
             §DATARS = %Addr(dsDataQ.DATARS);
             write I3DGXARR dsDSARC;
    Wenn das RPG-Programm den write-Befehl erreicht, bricht es ab und zwar so, dass ich den Abbruch weder mittels monitor-Gruppe, noch write(e) abfangen kann. Im RDi-Debugger sieht man nur, dass das Programm mit der Ausführung des write-Befehls endet.

    Das Tollste ist, dass der Satz trotz des Abbruchs völlig korrekt in I3DGXARC geschrieben wird.

    Beim interaktiven Aufrufen wird nur ein Fehler des aufrufenden Programms gemeldet, nämlich, dass der Aufruf fehlerhaft beendet wurde:

    Fehlermeldung:
    Code:
    Der Aufruf an *LIBL/I3DGXDATA wurde fehlerhaft beendet (C G D F)
    Ursache  . . . . : RPG-Prozedur I3DGXHOL in Programm I3DGXHOL hat bei 
      Anweisung 2367 Programm oder Prozedur *LIBL/I3DGXDATA aufgerufen; der Aufruf
      wurde fehlerhaft beendet. Ist der Name *N, handelte es sich bei dem Aufruf  
      um einen Bindeaufruf nach Prozedurzeiger.
    dspjoblog:
    Code:
    Anwendungsfehler. CEE9901 nicht überwacht durch I3DGXHOL bei Anweisung 
      0000002367, Instruktion X'0000'.
    Weitere Nachrichteninformationen:
    Code:
    Nachricht . . . :   Anwendungsfehler. CEE9901 nicht überwacht durch I3DGXHOL 
       bei Anweisung 0000002367, Instruktion X'0000'.                             
                                                                                  
     Ursache  . . . . :  Die Anwendung wurde abnormal beendet, da eine Ausnahme   
       aufgetreten ist, die nicht behandelt wurde. Der Name des Programms, an das 
       die nicht behandelte Ausnahme gesendet wurde, ist I3DGXHOL I3DGXHOL        
       I3DGXHOL. Das Programm wurde bei der/den HLL-Anweisung/en mit der/den ...
    Und das ist der SQL-Create-Befehl:

    Code:
    create table I3DGXARR (                  
                                                      
     NAME CHAR(128),                               
    (... weitere CHAR-Felder ...)
    Anz_BLAST INTEGER,
    (... weitere INTEGER-Felder ...)
    NR NUMERIC(7),    
    AENTMST TIMESTAMP, 
    AENDAT DATE
    );
    RENAME TABLE I3DGXARR TO SYSTEM NAME I3DGXARC;
    Die Datei hat eine verhältnismäßig große Satzlänge, 5801 Bytes bei 114 Feldern, aber das sollte doch kein Problem sein. Kann es vielleicht mit den INTEGER-Feldern zusammenhängen?

    Sonst: Wo kann ich weitere Informationen über den Programm-Abbruch finden?
    Hat jemand eine Idee, wo der Fehler liegt?

    Gruß und vielen Dank!
    Markus

  2. #2
    Registriert seit
    Aug 2001
    Beiträge
    2.873
    Was passiert denn, wenn Du anstatt der Pointer-Zuordnung eine zweite Datenstruktur definierst, diese sauber initialisierst (INZ) und anschließend mit EVAL-CORR befüllst?

    Code:
         D dsDataQ         DS                  LikeDS(DATATRNQRS)  INZ XML-DS definiert in Copyfile
         D dsDSARC         DS                  LikeRec(I3DGXARR:*OUTPUT) INZ
        /Free
           ....
           Eval-Corr DsDSARC = DsDataQ;
           write I3DGXARR dsDSARC;
    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

  3. #3
    Registriert seit
    May 2014
    Beiträge
    5

    Thumbs up

    Vielen Dank, Birgitta! Es ist mir äußerst peinlich, ich habe den Fehler jetzt gefunden.

    Dein "Vorschlag mit eval-corr" hat mich veranlasst, noch einmal die Datenstruktur mit dem Satzformat zu vergleichen und tatsächlich fehlten in der DS zwei Felder am Ende, die ich nachträglich eingebaut hatte. Dabei bin ich mir absolut sicher, dass ich die Datenstruktur entsprechend erweitert hatte. Anscheinend hatte ich das Copyfile mit der DS-Definition in meiner Testbibliothek mit dem Copyfile aus der Entwicklungsbibliothek überschrieben, das einen älteren Stand hatte (was eigentlich nicht hätte sein dürfen -- kennt jemand ein gutes Tool zur Versionskontrolle?)

    Vielen Dank nochmals!
    Markus

    PS: Liebe Admins, wenn hier Threads wegen Sinnlosigkeit gelöscht werden können -- nur zu!

  4. #4
    Registriert seit
    Mar 2002
    Beiträge
    5.287
    ... was hier passiert ist, ist doch exemplarisch:
    das Ausgangsproblem ist relativ überschaubar:
    - es gibt ein XML, das ins Programm eingelesen werden soll
    - es gibt eine Datei, in die Informationen aus diesem XML reingeschrieben werden soll
    Statt die naheliegende einfache Lösung zu wählen eine Struktur zum einlesen zu definieren, einlesen, benötigte Werte übertragen, schreiben, wird erheblich Gehirnschmalz verbraten, um ein paar Zeilen elementaren Code einzusparen.
    Dafür kauft man dann nicht unerheblich Probleme ein:
    - enge Kopplung zwischen dem XML und der Datei (wenn sich am XML was ändert, muss die Datei oder Logik geändert werden)
    - Verzicht auf alle Prüfungen des Compilers (per Pointer kriegt man alles aufeinander genagelt)
    - wesentlich verschlechterte Lesbarkeit des Programms.

    Meine Empfehlung:
    - immer an Lesbarkeit orientieren
    - einfach ist meist auch gut
    - nicht immer alles ausreizen, was man so alles kann

    D*B

    PS: Die runtime hat sich hier auch nicht mit Ruhm bekleckert, wenn ein write abschmiert, hat da auch nix in der Datei drinzustehen.
    Weitere Empfehlung:
    Commit einsetzen, da wäre dann wenigstens ein automatischer Rollback hinterhergekommen.
    AS400 Freeware
    http://www.bender-dv.de
    Mit embedded SQL in RPG auf Datenbanken von ADABAS bis XBASE zugreifen
    http://sourceforge.net/projects/appserver4rpg/

  5. #5
    Registriert seit
    May 2014
    Beiträge
    5
    Vielen Dank, Bender, für deine Antwort!

    Programme lesbar zu halten, ist auch mein Anliegen. Schon allein deswegen, damit ich selber sie nach ein paar Wochen noch verstehe.

    Hier geht es darum, dass ich ein XML-Dokument mit 114 möglicherweise interessanten Elementen in eine Datei schreiben möchte. Alle 114 Felder einzeln behandeln will ich nicht. Dies ist nämlich meines Erachtens ebenfalls eine Quelle für Fehler. (Die sich allerdings entschärfen lässt, indem man sich den Code generieren ließe; ich mache so was gerne - bitte nicht schlagen! - per Word-Serienbrief oder in Excel ... 114 Zeilen mit =" if "&A1&" <> *blank;"&zeichen(10)&" eval dsDATA."&A1&" = "&A1&";"&zeichen(10)&" endif;" oder sowas.)

    Wie wäre dein Vorschlag? Eine Datenstruktur mit den Felddefinitionen brauche ich doch in jedem Fall. Die Kopplung zwischen XML und Datei ist wohl auch unerlässlich. Hier geht es um Werte zu bestimmten Objekten, zu denen wir Aktualisierungen erhalten. Später hole ich mir per "select feldname from I3DGXARC order by aentmst desc fetch first row only" den jeweils aktuellsten Wert. Mit prepared SQL ist das eine praktische Sache, die tatsächlich hilft, den Code lesbar zu halten.

    In Programmen, die das Archiv lesen, wird dann eine Prozedur verwendet, die ich in einem SRVPGM um das SQL herum gebastelt habe. Das sieht dann so aus:

    chrNeuName = getAktWert(objekt:'NAME');

    Durch den Pointer habe ich eine zweite Datenstruktur eingespart. Die Definition per Likerec macht deutlich, dass Satzformat und Datenstruktur übereinstimmen. Für mich schien das eine lesbare, vergleichsweise leicht verständliche Lösung zu sein.

    Was meinst du konkret mit "... die naheliegende einfache Lösung ... eine Struktur zum einlesen zu definieren, einlesen, benötigte Werte übertragen, schreiben"? Ich neige manchmal leider dazu, das Einfache zu übersehen und viel zu kompliziert zu denken.

    Struktur zum Einlesen - habe ich
    Einlesen - mache ich (XML-Into)
    Schreiben - mache ich -- neuerdings sogar ohne Abbruch :-)

    Vor allem das "benötigte Werte übertragen" macht mich neugierig; denn genau dieser Punkt hat mir Kopfzerbrechen bereitet und zu meiner Lösung geführt. Eval-corr macht es ja nicht unbedingt um Größenordnungen einfacher. Und das Schreiben -- wohin, wenn nicht in eine Datei, deren Aufbau sich am XML orientiert?

    Beste Grüße
    Markus

  6. #6
    Registriert seit
    Mar 2002
    Beiträge
    5.287
    Zitat Zitat von Scholli2000 Beitrag anzeigen
    Durch den Pointer habe ich eine zweite Datenstruktur eingespart.

    Vor allem das "benötigte Werte übertragen" macht mich neugierig; denn genau dieser Punkt hat mir Kopfzerbrechen bereitet und zu meiner Lösung geführt. Eval-corr macht es ja nicht unbedingt um Größenordnungen einfacher.
    ... wieso eingespart? kriegts Du die vom Gehalt abgezogen?
    Werte übertragen ist ne ganz stumpfe Angelegenheit.

    dateiRec.feld = xmlRec.feld;
    dateiRec.nocheineFeld = xmlRec.nocheinFeld;
    ...
    das könnte man auch auslagern als:
    dateiRec = mapXmlRec(xmlRec);

    Was man hier gegenüber der Pointer Mimik gewinnt ist, dass man pro Feld Verträglichkeit vom Compiler geprüft kriegt, vieles schon zur Compilezeit, statt zur Ausführungszeit.

    D*B

    PS: das mit dem "generieren" per Word und Excel ist als reine Notwehr legitim, vernünftigere Editoren als dieses RDI Gesums können da vieles von sich aus.
    AS400 Freeware
    http://www.bender-dv.de
    Mit embedded SQL in RPG auf Datenbanken von ADABAS bis XBASE zugreifen
    http://sourceforge.net/projects/appserver4rpg/

  7. #7
    Registriert seit
    May 2014
    Beiträge
    5
    Okay, die Einsparung war wohl Blödsinn, zumal ich ja nur den Speicherplatz einspare und die Programmlogik nicht schlanker wird, weil ich die Datenstruktur als Variable trotzdem benötige.

    Mein Gedanke war, dass das Programm übersichtlicher bleibt, wenn ich eben nicht alle Felder von einer Seite auf die andere schiebe. Aber du hast natürlich recht, dass das unvorhersehbare Folgen haben kann, wenn einmal versehentlich Unterschiede vorhanden sind -- wie oben geschehen.
    Deinen Vorschlag mapXmlRec finde ich insofern attraktiv, als ich damit weitergehende Prüfungen einbauen kann, falls diese einmal notwendig werden.

    Kurz gesagt: Du hast mich überzeugt.

    Besten Dank nochmals!
    Markus

    P.S: Abschließend würde mich noch brennend interessieren welche "vernünftigeren Editoren als dieses RDI Gesums" du mir empfehlen würdest. Ich bin mit RDI/LPEX halbwegs zufrieden -- bis auf die sehr schlechte Funktion zum Vergleichen von zwei Quellen, wofür ich immer noch Code/400 benutze. Ein eingebauter Code-Generator wäre auch was Feines -- hab nie daran gedacht, dass es sowas geben könnte.

  8. #8
    Registriert seit
    Mar 2002
    Beiträge
    5.287
    ... was Editoren angeht, bin ich ein wenig verwöhnt von Java, wo selbst ein noCost Produkt wie Eclipse im Bereich Source (setter/getter try/catch etc. generieren) und vor allem im Bereich Refactoring (rename von Komponenten automatisch durchgängig, Methoden ausglieder/verschieben etc.) Dinge anbietet, von dem man bei einem teuren RDI nur träumen kann. Das sieht von weitem wie Eclipse aus, kann aber von den wirklich wichtigen Dingen nix.
    Sorry, leider gibt es da wohl nix vergleichbares für RPG und Co.

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

  9. #9
    Registriert seit
    May 2014
    Beiträge
    5
    Nun ja, der RDi kann immerhin einem IF automatisch ein ENDIF hinzufügen. ;-)

    Gruß und nochmals danke!
    Markus

    (Das oben genannte Feature ist allerdings das erste, was ich nach einer Neuinstallation des RDi deaktiviere.)

Similar Threads

  1. FTP erstellt Datei auf fernem System - aber ohne Datenbankfelder
    By msost in forum NEWSboard Programmierung
    Antworten: 5
    Letzter Beitrag: 21-01-14, 11:31
  2. IFS per FTP auf NAS, aber nur geänderte Objekte
    By programmer400 in forum IBM i Hauptforum
    Antworten: 5
    Letzter Beitrag: 11-12-13, 11:14
  3. RUNSQLSTM falsch aber Interaktiv OK
    By BerndF in forum IBM i Hauptforum
    Antworten: 10
    Letzter Beitrag: 10-04-03, 07:01
  4. Antworten: 3
    Letzter Beitrag: 29-10-01, 10:07
  5. Wie schreibt man ein C/CPP Programm
    By Arbi in forum NEWSboard Server Software
    Antworten: 3
    Letzter Beitrag: 22-09-01, 10:28

Berechtigungen

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