PDA

View Full Version : ILE RPG und dynamisches Array



Squall
09-10-06, 12:42
Hallo,

ich versuche mich gerade an emb SQL mit Variablenübergabe über ein dyn. Array. Ich bekomme jedoch die Fehlermeldung:
*RNF0528 20 138 004500 Index ist für einen Namen, der keine Feldgruppe ist, nicht
zulässig; der Index wird ignoriert. Bei: Array(i)=FETCHDS

Hier der gesamte Code:

H DftActGrp(*NO) ActGrp(*CALLER)
H alwnull(*USRCTL)

D/COPY LIB/FILE,MEMBER

DAUFNEHM PR EXTPGM('SQLSAMPLE4')
D PARM1 like(Array2)
D PARM2 1A

DAUFNEHM PI
D Array like(Array2)
D fcall 1A

DArrayptr S * Inz(*Null)
DArray2 DS Dim(32767) Based(Arrayptr)
D likeds(DSLIB)

Di S 5S 0 inz(1)
Dj S 5S 0 inz(1)
DFetchds DS likeds(DSLIB)

C/EXEC SQL
C+ Declare MyCsr Cursor for
C+ Select * From LIB/FILE
C/End-Exec

C/EXEC SQL
C+ Open MyCsr
C/END-EXEC

/FREE
Arrayptr = %Alloc(%Size(Array) * i);
/END-FREE

C do *HIVAL
C/EXEC SQL
C+ Fetch MyCsr
C+ into :FETCHDS
C/END-EXEC
C if SQLCOD = 100
C or SQLCOD < *ZEROS
C eval fcall='E'
C leave
C endif
C eval Array(i)=FETCHDS
/Free
Arrayptr = %Realloc(Arrayptr: %Size(Array) * i);
/END-FREE
C eval i=i+1
C enddo
C/EXEC SQL
C+ Close MyCsr
C/END-EXEC
C return

Ich hätte auch noch eine Frage. Und zwar geht diese Übergabe so wenn das Array in VARP auch so definiert ist wie dieses?(mit dem Pointer und dim(32767) ) Oder wie müsste ich es definieren, denn ich weiß ja nicht wie groß das Array ist das ich zurückgebe. feste Werte sind schlecht weil sie entweder zu groß oder zu klein sind. Darum wollte ich es mit einem Dynamischen Array machen.

Gruß Martin

Fuerchau
09-10-06, 12:54
Dynamische Arrays gibts in RPGLE nicht.
Beim Fetch musst du noch "for n rows" angeben, damit das Array gefüllt wird.
Ich glaube in SQLERR3 steht dann die Anzahl der gelesenen Sätze.
Das Ganze nennt man im Übrigen Block-Fetch.

Ansonsten berechne mal die Größe für deinen Alloc, der darf 16MB nicht übersteigen.

Squall
09-10-06, 13:38
Wenn es dyn. Array in ILE RPG nicht gibt warum schimpft der Compiler dann nicht bei dem Alloc? Zzt. sieht es ja nur so aus als ob es Probleme beim hin und herschieben des Arrays geben würde. (Und jetzt beim korrekten Zuweisen der Daten)

EDIT: Ich habe mir gerade mal den Block-Fetch angeschaut. Nur in welches Array schreibt er die Row(in Array(1) 2,3,...,zb bei for 1 row)? Angabe der Row ist ja nicht erlaubt.


Dynamische Arrays gibts in RPGLE nicht.
Beim Fetch musst du noch "for n rows" angeben, damit das Array gefüllt wird.
Ich glaube in SQLERR3 steht dann die Anzahl der gelesenen Sätze.
Das Ganze nennt man im Übrigen Block-Fetch.

Ansonsten berechne mal die Größe für deinen Alloc, der darf 16MB nicht übersteigen.

Fuerchau
09-10-06, 15:18
Stimmt, er startet immer beim 1. Element.

Und was deinen ALLOC angeht, klar streikt der nicht. Deine Tabelle ist aber immer noch 32767 Elemente lang. Du bekommst nur beim Zugriff auf die Variablen einen MCH. Du kannst sogar auf fremde Speicherbereiche kommen.

Wichtig ist, dass du bei den %lokup, %sort usw. immer die Anzahl Elemente angibst, sonst knallst.

Das ist das Gleiche, wie die Definition eines Übernahme-Parameters (*ENTRY, PLIST) in Ausprägung X, und zur Laufzeit dann CALL mit Y.
Der Compiler kann das nicht prüfen.

Squall
09-10-06, 15:29
Ja richtig dynamisch ist das Array nicht, aber ansatzweise bis zu der maximalen Größe.

Eine Frage hätte ich noch und zwar habe ich ja bei PR/PI meine Arrays mit like (Array2) definiert. Dh sie müssten(?) doch auch Arrays mit einer Größe von X sein(je nachdem wie groß ich Array2 definiert habe) oder? Warum sagt er dann ein Index sei nicht zulässig?


Stimmt, er startet immer beim 1. Element.

Und was deinen ALLOC angeht, klar streikt der nicht. Deine Tabelle ist aber immer noch 32767 Elemente lang. Du bekommst nur beim Zugriff auf die Variablen einen MCH. Du kannst sogar auf fremde Speicherbereiche kommen.

Wichtig ist, dass du bei den %lokup, %sort usw. immer die Anzahl Elemente angibst, sonst knallst.

Das ist das Gleiche, wie die Definition eines Übernahme-Parameters (*ENTRY, PLIST) in Ausprägung X, und zur Laufzeit dann CALL mit Y.
Der Compiler kann das nicht prüfen.

B.Hauser
09-10-06, 17:37
Hi,

bei der Definition über Like(Array) wird nur die Feld-Beschreibung, nicht jedoch die Anzahl der Feldgruppen-Elemente definiert, d.h. Du musst jeweils die (maximale) Anzahl der Feldgruppen-Elemente angeben, z.B. DIM(9999).

Birgitta

Fuerchau
09-10-06, 19:56
Bei der Übergabe von Arrays musst du aber gaaaaaaanz vorsichtig sein.
Wenn du nämlich die Anzahl der Elemente nicht irgendwo austauschst wirst du später schwere Pufferüberschreibungen riskieren.
Gut, im Gegensatz zu Microsoft wird das nie zu ausführbarem Code führen, aber wenn du da in VARPG bist, wer weiß welche Tricks für Viren es da gibt.

Aber ehrlich:
Wenn du einer Prozedur ein Array übergibst, dann musst du ihm auch sagen wieviele Element da drin sind.
Umgekehrt gilt natürlich das selbe.

Squall
10-10-06, 08:22
Hallo,

Ja das mit den Dim(XYZ) hatte ich gestern abend durch ausprobieren noch herausgefunden. Mit einem fest definiertem Array funktioniert es jetzt.

Ich kann der Methode nicht sagen wieviele Elemente das Array genau hat, da der SQL und die Allocierung ja dort stattfindet. Die Frage wäre ob ich das Array gefahrenfrei einfach so zurückgeben kann, bzw ob das überhaupt so funktioniert. Das Array in VARPG wurde zwar auch auf die max. Größe definiert es wurde jedoch noch kein Speicher allociert, da ich ja nicht weiß wieviel ich allocieren müsste.

Gruß Martin

Fuerchau
10-10-06, 08:33
Das Übergeben von ARRAYS ist natürlich sehr kritisch zu betrachten, da RPG eben keine Dynamik kennt.
Egal ob du den Parameter verändert oder einen "return variable" kodierst, im Zusammenspiel VARPG (Client) und AS/400-Programm wird generell die definierte Struktur übertragen !

Also:
Wenn VARPG als Parameter ein Array mit 1000 Elementen übergibt, weiß der Compiler, dass eine Speicherbereich von 1000 Elementen zu übertragen ist.
Der Service gibt dann andererseits den selben Speicherbereich auch wieder zurück, und zwar unabhängig davon, ob dieser auch tatsächlich verändert wurde (ich glaub nicht, dass dort ein Before-/Afterimmage-Abgleich stattfindet).

Es gibt also generell einen Unterschied zwischen einem lokalen Call der tatsächlich per Reference Parameter austauscht und einem Remote-Call, der Parameter ja übers Netzwerk austauscht.

Da empfehle ich dir eher wieder SQL !
Definiere eine externe Prozedur, die du mit Parametern aufrufst und die dir ein Resultset zurückgibt (was dann auch ein Array sein kann, siehe "SET RESULTSET").

Squall
10-10-06, 08:53
Ich benutze ja SQL wollte mir nur die verschiedenen Möglichkeiten der Rückgabe anschauen, vergleichen und mir dann das Beste heraussuchen. Die Methode mit festen Arrays und Schaltern (Mehrmalsaufruf, einmal pro Satz) funktioniert ganz gut ich wollte mich nur noch weiter umschaun.

Gruß Martin