PDA

View Full Version : dyn. SQL im RPG IV



ehilbig
29-07-03, 10:05
hallo,

bin noch etwas unerfahren mit embedded sql.

Ich möchte ein dynamisches sql mehrfach verarbeiten - es geht um ein Übersichtspgm (Subfile) mit div. Selektionen/Sortierungen.
Ich def. also eine Abfrage, öffne sie & lese, am Ende close cursor - alles ok.
Ausgabe auf BS - jetzt eine andere Selektion - Wenn ich dann die Abfrage ändere, wieder öffne & lesen will bekomme ich den SQL-Code -501 (cursor not open)

- wie kann ich das verhindern?

Fuerchau
29-07-03, 10:20
Parametrierte Abfragen werden so definiert:

/exec sql
+declare cursor mycursor for
+Select field1, field2, ....
+from myfile
+where key1=:mykey1 and key2=:mykey2 ...
/end-exec

Um die Abfrage dann auszuführen muss die Abfrage natürlich immer neu geöffnet werden:

/exec sql open mycursor
/end-exec

do *hival
/exec sql
+fetch mycursor into :myfield1, :myfield2, ...
/end-exec

if sqlcod < *zero
or sqlcode = 100
leave
endif

:
write MySubfile
:

enddo

/exec-sql close mycursor
/end-exec

ehilbig
29-07-03, 10:37
danke,
leider hilft mir das nicht weiter - ich will es mal als Beispiel bringen:


eval abfrage = 'select * from myfile where feld1 = sel1 and
feld2 = sel2 order by key1'

/exec sql prepare s1 from :abfrage
/end-exec

/exec sql declare c1 cursor for s1
/end-exec


/exec sql open c1
/end-exec


dow sqlcod <> 100

/exec sql fetch c1 into :myfile
/end-exec

if sqlcod = 100
/exec sql close c1
/end-exec
leavesr
endif

write subfile

....


exfmt sfcontrol

wenn neue Selektion:

eval abfrage = 'select * from myfile where feld2 = sel2 and
feld4 = sel4 order by key2, key4'

danach schicke ich das Pgm wieder zum "prepare s1"
und lasse es da weiter laufen (ist in meinem Pgm. eine Subroutine)

B.Hauser
29-07-03, 12:52
Hallo,

nur so eine Vermutung:
Ist die Reihenfolge in Deiner Quelle genau so wie angegeben (unabhängig von der Ausführung von Subroutinen)?

Wenn nein, versuche Deinen Code so zu stricken:

1. Füllen Command
2. Declare
3. Close (mache ich immer nochmals zur Sicherheit)
4. Open
5. Fetch

Wir hatten diesbezüglich Probleme, als wir beim statischen SQL das Declare-Statement in die *INZSR gelegt haben.
(allerdings war das noch unter RPGIII).

Sonst sieht der Code in Ordnung aus.

Birgitta

ehilbig
29-07-03, 13:07
danke,

ich habe den close vor dem open eingebaut, aber das war's leider auch nicht. Die Reihenfolge ist genau, wie Du es beschrieben hast, wenn sie nicht stimmt gibt's einen Abbruch bei der Umwandlung - ich denke, daß der SQL-Precompiler von oben nach unten geht & die Abfolge von Subroutinen nicht beachtet.

Fuerchau
29-07-03, 14:07
Die Reihenfolge von CLOSE / OPEN in der Quelle spielt keine Rolle. Einzig der DECLARE CURSOR muss in der Quelle vor der ersten Nutzung mit OPEN / FETCH / CLOSE liegen.
Auch der PREPARE kann in der Quelle liegen wo er will.

Prüfe jedoch mal, ob der PREPARE nicht bereits einen SQLCOD <> 0 liefert, ich glaube hier liegt ggf. das Problem.
Der CLOSE schließt ggf. den CURSOR nicht tatsächlich (SQL-Optimizer), so dass der PREPARE fehlschlägt.

Wenn Du vor Aufruf des Programmes mittels "STRDBG UPDPROD(*YES)" den Debugmodus startest, kannst du im Joblog detailierte Meldungen sehen.

Mit ENDDBG beendest du den Modus.

Achte bei der Umwandlung mal darauf wie die Option CLOSQLCSR gesetzt ist.

B.Hauser
29-07-03, 14:18
Die Reihenfolge Close/Open spielt tatsächlich eine Rolle.
Wenn z.B. folgendes Szenario stattfindet.

Cursor wurde geöffnet
Alle Sätze oder einige Sätze wurden mit Fetch in einer Schleife gelesen.
Es wurde kein Close gesetzt. (z.B. Schleife wurde nicht mit SQL-Code 100 verlassen)
Ein erneuter OPEN ist jetzt wirkungslos. (im Gegensatz zu einem SETLL im RPG)

CLOSQLCSR bewirkt nicht unbedingt, dass der Cursor geschlossen wird.
Sondern nur, ob der bereits gefundene Zugriffs-Weg beim nächsten Aufruf wieder verwendet wird.

Bei obigem Beispiel könnte es sogar sein, dass beim erneuten Programm-Aufruf keine Sätze mehr angezeigt werden, da der Cursor nicht geschlossen wurde, und alle Sätze verarbeitet wurden.

Birgitta

mk
29-07-03, 15:06
Hallo

vielleicht noch ein Tipp :

Wenn Du das Programm mit STRDBG durchgehst dann
schau Dir mal nach den einzelnen SQL Aktionen
den SQLCODE an.

Zusätzlich könnte das JOBLOG noch einen Fehler hergeben.


Gruss Michael

ehilbig
29-07-03, 15:39
hallo & vielen Dank für die Tips,

der Tip mit der Umwandlung war der Hit:

mit commit *none, closqlcsr *endmod & dlyprp *yes

hat's geklappt


also danke nochmal

gruß

lisa :)

Fuerchau
29-07-03, 16:57
@Birgitta

Ich meinte ja nicht die Reihenfolge der Durchführung von OPEN/CLOSE sondern nur der Ort in der Quelle.;)

Das Hauptproblem mit dynamischen SQL's sind die Resourcen, die intern verwendet werden.
Da der DECLARE CURSOR nicht dynamisch ist sondern zur Compilezeit bestimmt wird, wird auf die Resource Statement konstant verwiesen.

Erst wenn der Cursor also tatsächlich geschlossen ist, wird auch die Resource Statement wieder freigegeben.

Ein erneutes PREPARE kann somit nicht erfolgreich sein.

Durch die Option CLOSQLCSR(*ENDMOD) wird der Cursor durch verlassen des Moduls gelöscht und das Statement wieder freigegeben. Der Defaultwert ist ansonsten *ENDACTGRP, was die Resourcen über die gesamte Programmlaufzeit belegt.

Cursor werden auch durch COMMIT gelöscht, wenn nicht explizit im DECLARE CURSOR ... WITH HOLD definiert wurde.
Also auch ein Commit würde die Resource Statement in diesem Fall freigeben.