-
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
-
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
-
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!
-
... 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.
-
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
-
Zitat von Scholli2000
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.
-
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.
-
... 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
-
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
-
By msost in forum NEWSboard Programmierung
Antworten: 5
Letzter Beitrag: 21-01-14, 11:31
-
By programmer400 in forum IBM i Hauptforum
Antworten: 5
Letzter Beitrag: 11-12-13, 11:14
-
By BerndF in forum IBM i Hauptforum
Antworten: 10
Letzter Beitrag: 10-04-03, 07:01
-
By VauH in forum IBM i Hauptforum
Antworten: 3
Letzter Beitrag: 29-10-01, 10:07
-
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
-
Foren-Regeln
|
Erweiterte Foren Suche
Google Foren Suche
Forum & Artikel Update eMail
AS/400 / IBM i
Server Expert Gruppen
Unternehmens IT
|
Kategorien online Artikel
- Big Data, Analytics, BI, MIS
- Cloud, Social Media, Devices
- DMS, Archivierung, Druck
- ERP + Add-ons, Business Software
- Hochverfügbarkeit
- Human Resources, Personal
- IBM Announcements
- IT-Karikaturen
- Leitartikel
- Load`n`go
- Messen, Veranstaltungen
- NEWSolutions Dossiers
- Programmierung
- Security
- Software Development + Change Mgmt.
- Solutions & Provider
- Speicher – Storage
- Strategische Berichte
- Systemmanagement
- Tools, Hot-Tips
Auf dem Laufenden bleiben
|
Bookmarks