View Full Version : User Defined Function in SQL, Datumsübergabe an Serviceprogramm
dschroeder
28-11-14, 09:23
... einfach eine 2. procedure mit auf iso angepasster Schnittstelle aus demselben modul exportieren, die den Aufruf an die bereits implementierte durchreicht und fertig ist. Da RPG (leider) nicht überladen kann, muss die halt einen anderen Namen haben (suffix iso).
Ansonsten gehören die Aufrufe der function ohnehin im vie layer gekapselt, sodass ein cast von date nach alfa im Aufruf auch kein drama wäre.
D*B
Vielen Dank.
Genau das Prinzip verfolgen wir ja im Moment. Wir schreiben einen Adapter, der das Datum umwandelt und dann die eigentliche Procedure aufruft. Ich finde das nur sehr lästig. Ich habe 2 Sprachen (SQL und RPG) und in beiden habe ich Datumsfelder. Es wäre natürlich schön, wenn die beiden Sprachen ihr Parameter dann auch untereinander aushandeln könnten.
Dieter
Deshalb behelfen wir uns immer damit, ein zusätzliches RPG-Serviceprogramm zu erstellen
...dazu brauchts kein weiteres SRVPGM, diese procedure gehört in das Modul mit der Implementierung!!!
dschroeder
28-11-14, 09:50
Beide Procedures in einem Serviceprogramm fände ich in diesem Fall auch besser. Geht aber bei uns wegen unseres Toolings (im Moment) nicht.
dschroeder
28-11-14, 09:55
SQL interessiert das Datums-Format überhaupt nicht, sondern arbeitet immer mit der scaliger no.
Das Datums-Format wird nur dazu verwendet, das Datum lesbar zu machen.
Das Problem ist die Parameter-Übergabe von/an RPG. In RPG wird ein Datum immer in eine alphanumerische Darstellung konvertiert. SQL kann auf der anderen Seite alphanumerische Strings im Format JJJJ-MM-TT, TT.MM.JJJJ und MM/TT/JJJJ als Datum identifizieren und problemlos umsetzen. Wird aus einer SQL-Funktion ein Datum an RPG übergeben, wird dieses in eine alphanumerische Darstellung im *ISO-Format (JJJJ-MM-TT) konvertiert und übergeben.
... und an dieser Stelle kracht RPG.
Was passiert eigentlich, wenn Du die Original-RPG-Funktion, die ein echtes Datum erwartet registrierst, den Datum-Parameter jedoch als CHAR(10) definierst?
Dann überlädst Du die SQL-Funktion und definierst den Datums-Parameter als echtes Datum. In dieser Funktion, konvertierst Du das Datum in eine alphanumerische Darstellung im *Europäischen Format (CHAR(Datum, EUR) und rufst die Origianl-Funktion mit diesem Parameter auf.
Zu Deiner Idee mit dem ISO-Format. Habt Ihr bei den Datums-Feldern im Prototypen ein Datums-Format hinterlegt?
Wenn nein solltet Ihr das tun (DATFMT(*ISO)). Die vorhandenen RPG-Programme sollten dann die Funktion ohne Umstellung des Formats aufrufen können. Die Runtime konvertiert das Datum in das erwartete Format.
Birgitta
Birgitta
Ich habe das eben nochmal durchprobiert:
1. Wenn RPG das Datumsfeld als date(*iso) empfängt und im SQL das Feld als date deklariert ist, klappt es.
2. Wenn RPG das Datum als date(*eur) empfängt und im SQL das Feld als char(10) (oder auch varchar(10) ) deklariert ist, klappt es nicht. Dann kommt der Fehler, dass die SQL-Funktion das Serviceprogramm gar nicht finden kann.
Dieter
Für SQL muss das Feld als DATE definiert sein, da eben an die Prozedur ein DATE übergeben wird!
Genauso muss auch ein Returnwert als DATE definiert sein.
Nun arbeitet halt eine SQL-Function/Prozedur grundsätzlich mit *ISO.
Unabhängig von der H-Bestimmung *EUR lässt sich das Format eines D-Feldes individuell festlegen.
Die Parameter der SQL RPGLE-Prozedur können also mit DATFMT(*ISO) arbeiten. Bei der Übertagung zwischen D-Feldern erfolgt eine Anpassung.
Der Aufruf via SQL ist für alle Sprachen gleich, egal ob STRSQl, embedded SQL, ODBC/JDBC (Java, OpsNav, u.v.m).
Was ich halt meinte, dass man die Aufrufart einer RPG-Prozedur nicht mischen sollte.
Durch "parameter style General" kann ich die Prozedur via SQL oder eben auch native via CALLP verwenden was eben zu verhindern gilt.
Schreibe also eine RPGLE-Prozedur mit *ISO als Datumsformat. Alle RPGLE-Programme mit *EUR als Datumsformat übergeben an SQL ein Datum immer in *ISO!
Schau dir mal nämlich den Spool an. Die SQLnnnn-Variable ist mit DATFMT(*ISO) definiert und bei der Zuweisung von/nach konvertiert die Runtime zwischen *ISO und *EUR.
Deshalb gibt es ja häufig Laufzeitfehler bei falschen Datenformat von der RPG-Runtime und nicht von SQL wenn die Formate nicht konvertierbar sind.
dschroeder
01-12-14, 08:31
Danke für deine Ausführungen. Bisher verfolgen wir das Ziel, ein Serviceprogramm von beiden Umgebungen (SQL und RPG) aufrufen zu können. Wenn wir nicht gerade diese Datumsproblematik haben, klappt das ja auch.
Ich danke nochmals allen für Ihre Antworten.
Dieter.
Was ich halt meinte, dass man die Aufrufart einer RPG-Prozedur nicht mischen sollte.
Durch "parameter style General" kann ich die Prozedur via SQL oder eben auch native via CALLP verwenden was eben zu verhindern gilt.
... Einspruch: grundsätzlich gilt, dass eine Funktionalität auch nur eine Implementierung hat. Wenn man aus irgendeinem Grund, sei es technische Restriktion (wie hier), oder auch Bequemlichkeit, oder Lesbarkeit mehrere Varianten für die Parameterschnittstelle braucht, so bieten moderne Programmiersprachen (=> RPG ist keine davon) hierfür die Möglichkeit der Überladung.
Bei überladenen Funktionen ist es gängige Praxis, dass es hier nur eine Impelmentierung gibt und die anderen als Adapter fungieren, sprich: Parameterschnittstelle anpassen und die eigentliche Implementierung aufrufen.
Das Problem in diesem Fall ist rein hausgemacht: man hat 2 unsinnige Standards (alle Datumsfelder *EUR und nur eine exportierte Funktion pro SRVPGM) die beide zusammen zu Aufwand führen. Der saubere Weg wäre:
- beide Standards ändern und alle betroffenen Funtionen einfrieren (deprecated), d.h. ist Änderung in der Funktion erforderlich wird die *ISO Schnittstelle im selben Modul zugefügt und die Implementierung dorthin verschoben, die *EUR Schnittstelle wird zum Adapter. Kommt eine Aufruf hinzu, wird die *ISO Variante verwendet und gegebenen Falls eingefügt. Bei neuen Funtionen wird gleich *ISO angelegt.
D*B
Dem kann ich nur zustimmen.
Allerdings finde ich persönlich eben "Parameter style General" eben bedenklich, da man nicht mit NULL und Fehlermeldungen (Diagnose) umgehen kann.
Der "SQL-Aufruf" ist dann wieder zu komplex bzw. lästig. Da kann ich ja dann auch wieder einen Wrapper drumrum stricken.
... da kommen wir uns schon näher. Bei sauberer Schichtentrennung zwischen Datenbank und Applikation werden SQL Functions nur im View Layer referenziert und da sollten sie keine Fehler zurückwerfen und NULL values lassen sich mit Coalesce rausmaskieren. Also ich bin bisher mit Parameterstyle general immer ausgekommen.
Sollte ich denn Parameterstyle SQL brauchen, dann wird eben wieder eine Procedure mit der erforderlichen Schnittstelle aus demselben Modul exportiert, die die vorhandene RPG procedure in diesem Modul benutzt. Im diskutierten Fall wäre das aber bei sinnigem Standard für Datumsfelder garnicht erforderlich und der Standard gehört geändert (wenn ich merke, dass ich mit dem Auto in eine Sackgasse gefahren bin, dann drehe ich auch sofort und fahre nicht erst bis zum rot/weiß gestreiften Balken).
D*B
dschroeder
01-12-14, 10:44
Ich kann die Argumente nachvollziehen, muss aber sagen, dass die Realität es nicht zulässt, jeden einmal definierten Standard nach Belieben zu ändern. Selbst wenn man erkennt, dass es aus heutiger Sicht besser gewesen wäre, einen anderen Standard zu verwenden. Ein Umstellung aller Programme auf *ISO würde eine Umstellung von mehreren tausend Programmen bedeuten. Selbst wenn wir das mit einem Sourceroboter erledigen würde, wäre eine gewisse Unsicherheit da, ob noch alles funktioniert und ob sich nicht doch irgendwo Algorithmen verstecken, die vom Datumsformat *EUR ausgehen.
Zu Dieters Beispiel mit der Sackgasse: Ich denke, wir sind nicht in einer Sackgasse, sondern eher auf einer unbequemen Nebenstraße und stellen nach 90 Prozent des absolvierten Weges fest, dass es inzwischen eine super ausgebaute Autobahn gibt. Da würde ich dann nicht umdrehen.:)
Dieter