Einen kurzen Überblick gibt Ihnen die Kurzinformation.
Der Zweck des Produktes Remote SQL (RSQL) ist es, dem Programmierer von Anwendungen auf einem PC zu gestatten, über eine Netzwerkverbindung auf Daten einer HP NonStop SQL/MP Datenbank zuzugreifen.
RSQL ist eine Erweiterung von Remote ENSCRIBE. Es wurde in Client/Server Architektur realisiert. Dabei stellt das HP-NonStop-System die Server-Maschine dar und der PC den Client. Folglich enthält RSQL zwei wesentliche Komponenten:
einen Serverprozess für die HP-NonStop-Seite
eine Funktions- bzw. Klassenbibliothek für die PC-Seite, mit deren Hilfe der Anwendungsprogrammierer in die Lage versetzt wird, seiner Anforderung gemäße Client-Programme zu schreiben.
Die Kommunikation zwischen diesen beiden Komponenten erfolgt mittels TCP/IP. Genaue Kenntnisse dieses Protokollstacks werden vom Programmierer jedoch nicht verlangt, da sämtliche Netzwerkzugriffe durch C++ Klassenbibliotheken verborgen werden. Im Gegenteil: der Anwendungsprogrammierer kann sich während der Entwicklung weitestgehend auf die eigentlichen SQL- und Datenbankproblematiken konzentrieren, ohne sich um Details der Transportschichten kümmern zu müssen.
Die folgende Graphik verdeutlicht das Zusammenspiel der einzelnen Komponenten am Beispiel eines Windows-Clients:
Der Server-Prozess auf dem NonStop-Server wird über den LISTNER-Prozess des TCP/IP gestartet, sobald ein Client-Programm (es können auch mehrere dieser Client-Systeme eingesetzt werden) dies erfordert, d.h. eine Verbindung (Connection) eröffnet.
Durch Aufruf der zugehörigen Klassenfunktionen kann das Anwendungsprogramm nun auf die SQL-Daten zugreifen, wobei die Klassenbibliothek die Aufträge über das TCP/IP-Netzwerk an den Serverprozess sendet. Dieser interpretiert die Aufträge und führt die entsprechenden SQL-Operationen aus.
Anschließend überträgt er die Antwortdaten an den PC. Diese werden nun dort in systemgerechte Datenformate konvertiert und dem aufrufenden Anwendungsprogramm bereitgestellt.
Die Installation ist in zwei Teile gegliedert, entsprechend der Aufteilung in Server und Client. Sie sollten jeweils erfahren sein im Umgang mit dem jeweiligen System.
Die Programmdatei RSQLSRV sollte sich normalerweise im Volume $SYSTEM.RSQL befinden. Es sind jedoch auch andere Volumes möglich.
Dieses Serverprogramm wird von dem LISTNER-Prozess gestartet, welcher im Standardumfang des TCP/IP-Pakets von HP enthalten ist. Der Start erfolgt in dem Moment, in dem auf irgendeinem Client im Netz eine RSQL-Verbindung geöffnet wird. Dann nämlich wird eine TCP/IP-Verbindung zu demjenigen TCP-Port hergestellt, der für den RSQL-Dienst als 'well-known' Port definiert wurde (s.u.). Abhängig vom Inhalt der Textdatei PORTCONF (s.u.) startet der LISTNER nun den zugehörigen Serverprozess, in diesem Fall 'RSQLSRV'. Für jede Verbindung wird somit auch jeweils ein neuer Serverprozess kreiert.
Der Remote-SQL-Server überprüft in der Startphase die auf der PC-Seite bei dem entsprechenden Funktionsaufruf verwendete Benutzerkennung und das Passwort. Bei Erfolg wird dem Prozess die entsprechende User-ID zugeordnet.
Befolgen Sie bitte zur Installation die folgenden Schritte:
Schritt 1: Übertragen der Programmdatei RSQLSRV
Mittels eines Filetransferprogrammes (z.B. FTP, welches Bestandteil jedes TCP/IP-Softwarepakets ist) wird die ausführbare Objektdatei RSQLSRV auf das HP-NonStop-System übertragen, wobei im folgenden als Zieldateiname $SYSTEM.RSQL.RSQLSRV angenommen wird. Beachten Sie, dass die Übertragung im Binärmodus erfolgen muss. In FTP erreicht man dies durch Eingabe des Befehls 'bin' .
Schritt 2: Einrichten der Programmdatei RSQLSRV
An einem TACL-Bildschirm werden nun folgende Befehle eingegeben:
LOGON SUPER.SUPER
VOLUME
$SYSTEM.RSQL
- hier befindet
sich die Programmdatei
FUP ALTER RSQLSRV, CODE 100
-
deklariert die Datei als ausführbares Programm
SQLCOMP /IN RSQLSRV/ CATALOG $DATA.SQL
- registriert das Programm bei
NonStop-SQL
Im letzten Befehl ist statt '$DATA.SQL' ein beliebiger auf dem System gültiger SQL-Katalog anzugeben.
Schritt 3: Bearbeiten der Datei PORTCONF
Diese Datei befindet sich normalerweise in $SYSTEM.ZTCPIP.PORTCONF und sollte bereits existieren. Sie stellt die Verbindung zwischen den TCP-Portnummern und den Namen der Programmdateien her, die die entsprechenden Serverprogramme enthalten. Für RSQL ist hier folgende Zeile einzutragen:
741 $SYSTEM.RSQL.RSQLSRV -p150
Der Name der Programmdatei ist hierbei entsprechend der tatsächlichen Installation anzugeben. Die Portnummer können Sie selbst bestimmen. Beachten Sie dabei jedoch, dass Ports unter 1024 nur von Supervisor-Prozessen verwendet werden können, was hier jedoch der Fall ist. Clientprogramme wissen in diesem Fall, dass der Server "vertrauenswürdig" ist, da er nur von einem authorisierten Systemadministrator eingerichtet worden sein kann. Beachten Sie weiterhin, dass Ports oberhalb 1024 dynamisch von anderen Anwendungsprogrammen verwendet werden. Sie können daher nicht sicher sein, dass der konfigurierte Port später tatsächlich verfügbar ist. In den weiteren Beispielen wird die hier angegebene Portnummer 741 weiter verwendet werden.
Der Parameter -p150 legt die Prozesspriorität auf 150 fest. Der LISTNER läuft normalerweise mit einer hohen Priorität, die er auf nachgelagerte Prozesse überträgt. Dies ist bei komplexen SQL-Abfragen jedoch unter Umständen nicht gewünscht und kann hier beinflusst werden.
Schritt 4: Neustart des Listner-Prozesses
Nachdem die oben genannten Schritte durchgeführt wurden und damit alle benötigten Dateien auf dem HP-NonStop-System-System verfügbar sind, muss der Listner-Prozess neu gestartet werden, um die Änderungen wirksam zu machen. Ansonsten würden die Änderungen erst beim nächsten Systemstart aktiviert werden.
Stoppen Sie den Listner-Prozess
Starten Sie den Listner-Prozess erneut
Leider kann hier keine allgemeingültige Vorgehensweise angegeben werden, da diese Schritte auf nahezu jedem System anders erfolgen müssen. Als Hinweis kann dabei die Startup-Prozedur des TCP/IP-Systems dienen.
Damit ist die Installation der Serverseite abgeschlossen.
Auf der PC-Seite sind bei der Installation von RSQL selbst keine Programme zu installieren, sondern lediglich einige Dateien, die im folgenden beschrieben werden. Diese Dateien werden vom Anwendungsentwickler verwendet, um eigene Anwendungsprogramme zu übersetzen und zu binden. Dies ist in Kapitel 3. detailiert beschrieben.
Die erwähnten Dateien werden nur auf dem PC benötigt, auf dem die Entwicklung, d.h. die Übersetzung Ihres Anwendungsprogrammes erfolgt. Das fertiggestellte Programm kann später auch auf anderen Systemen eingesetzt werden, ohne dass hierfür eine RSQL-spezifische Installation notwendig wäre.
Zunächst sind diese Dateien jedoch auf dem Entwicklungs-PC zu installieren:
Schritt 1: Anlegen eines Verzeichnisses zur Aufnahme der Dateien
Sie können hier ein beliebiges Verzeichnis wählen. Dieses kann sich sowohl auf der Festplatte des Entwicklungs-PCs, als auch auf einem über Netzwerk erreichbaren Fileserver befinden. In den folgenden Beispielen wird hier das Verzeichnis C:\RSQL verwendet.
Schritt 2: Kopieren der Dateien in das angelegte Verzeichnis
Kopieren Sie die folgenden Dateien von der Auslieferungsdiskette in das in Schritt 1 angelegte Verzeichnis:
NSSQL.H
RSQL.H
RSQLERR.H
RENSCRIB.H
RSQL.LIB
Damit ist die Installation der PC-Seite abgeschlossen. Wird die Source-Version der Bibliothek verwendet, sind statt der LIB-Datei die drei Dateien RSQLCS.H, RENSCRIB.C und RSQL.CPP zu installieren.
Dieses Kapitel beschreibt die Programmierschnittstelle zu RSQL für den Programmierer von Anwendungsprogrammen, die auf NonStop-SQL/MP Daten über Netzwerk zugreifen sollen.
RSQL verwendet zur Ausführung von Datenbankoperationen dynamische SQL-Anweisungen. Um solche SQL-Anweisungen in ein Anwendungsprogramm, welches auf einem Client-System laufen soll, aufzunehmen, stellt RSQL eine Bibliothek von Funktionen bzw. C++-Klassen zur Verfügung.
Die gesamte Netzwerkanbindung und die Realisierung des Client/Server-Systems werden in den Klassenbibliotheken (mit Ausnahme der Netzwerkadresse des HP-NonStop-Systems) verborgen.
Noch ein Wort für C++-Neulinge: die RSQL Klassenbibliotheken fordern keine tiefgehenden Kenntnisse der Programmiersprache C++. Wenn Sie bereits erfahren sind im Umgang mit C, so wird Ihnen die Verwendung von RSQL kaum Schwierigkeiten bereiten. Folgen Sie einfach den Beispielen. Auf der anderen Seite nimmt Ihnen C++ aber eine Menge Arbeit ab und sorgt unter anderem dafür, dass Ihre Programme zuverlässiger ablaufen.
Die vorliegende Version ist auf die Verwendung des Visual-C++ Compilers der Firma Microsoft ab Version 4.0 ausgelegt. In den folgenden Beispielen wird daher auf diesen Compiler und die zugehörige Entwicklungsumgebung Microsoft Developer Studio eingegangen.
Im folgenden wird davon ausgegangen, dass Sie den Umgang mit dem Microsoft Developer Studio bereits kennen. Daher wird nicht jeder Schritt im Einzelnen erläutert. Folgen Sie den folgenden Schritten, um ein neues Projekt mit Verwendung von RSQL anzulegen:
Starten Sie das Microsoft Developer Studio
Legen Sie einen neuen Project Workspace an.
Wählen Sie im Menü Build den Punkt Settings.
Gehen Sie auf die Unterseite C/C++
Wählen Sie die Category: Preprocessor
In das Feld Additional include directories geben Sie den Namen des Verzeichnisses ein, in welches Sie die Dateien des RSQL Paketes installiert haben, also z.B. C:\RSQL
Gehen Sie auf die Unterseite Link
Wählen Sie die Category: General.
Im dem Feld Object/library modules hängen Sie hinter die bereits eingetragenen Bibliotheken folgende an: wsock32.lib
Wählen Sie im Menü Insert den Punkt Files into Project
Wechseln Sie in das Installationsverzeichnis von RSQL, also z.B. C:\RSQL
Wählen Sie die Datei RSQL.LIB aus.
Fügen Sie nun wie gewohnt Ihre C++ Quellcode-Dateien in das Projekt ein. Beachten Sie dabei, dass Sie RSQL-Funktionen nur innerhalb von CPP-Dateien, nicht aber innerhalb von C-Dateien verwenden können.
Sie können dieses Projekt nun mit den gleichen Arbeitsschritten übersetzen und starten, wie Sie dies bereits von anderen Visual-C/C++-Projekten her kennen.
Zur Ausführung des Programmes auf anderen Rechnern benötigen Sie keine weiteren Komponenten aus dem RSQL-Paket. Achten Sie jedoch darauf, dass TCP/IP als Netzwerkprotokoll auf dem Rechner verfügbar ist.
RSQL stellt dem Programmierer eine Bibliothek von C++-Klassen zur Verfügung, mit deren Hilfe er innerhalb seiner Anwendung
eine Verbindung zum HP-NonStop-System herstellt
SQL-Statements übersetzt
Informationen über Datenformate erhält
übersetzte SQL-Statements ausführt
Daten aus der Datenbank auslesen kann.
Dieser Abschnitt enthält zum einen die Referenz dieser API und andererseits einige Hinweise und Beispiele zu deren Anwendung.
Um RSQL innerhalb Ihrer Anwendung benutzen zu können, ist es erforderlich die Datei rsql.h mittels der Präprozessoranweisung #include in jede CPP-Datei einzubinden, in welcher Sie solche Funktionen verwenden möchten. In dieser Datei und in den durch diese ebenfalls eingebundenen Dateien befinden sich sämtliche Deklarationen und Definitionen der in RSQL verfügbaren Datentypen.
Bevor die einzelnen Daten- bzw. Klassentypen im Detail beschrieben werden, soll hier kurz ein Überblick geboten werden.
Ein typischer Programmablauf beginnt im allgemeinen mit dem Erzeugen eines Objektes vom Typ RSQL_Connection. Dies kann z.B. dadurch erfolgen, dass dieses Objekt als statische Variable oder aber als Auto-Variable einer Funktion definiert wird. Die erste Methodenfunktion, die Sie aufrufen ist Connect. Unter Angabe der Netzwerkadresse des HP-NonStop-Systems und einer dort gültigen Benutzerkennung wird eine Verbindung zu diesem Rechner hergestellt und ein dieser Verbindung zugehöriger RSQL-Serverprozess gestartet.
Ist die Verbindung einmal hergestellt, so können Sie weitere Methoden von RSQL_Connection verwenden, um Transaktionen zu steuern, einfache SQL-Befehle auszuführen, oder komplexere SQL-Anweisungen zu übersetzen. Letzeres geschieht mittels der Methode Prepare, der Sie den Text des SQL-Befehls übergeben. Diese erzeugt ein Objekt der Klasse RSQL_Statement. Dies ist auch die einzige zulässige Methode, ein solches Objekt zu erzeugen, da die Klasse keinen öffentlichen Konstruktor besitzt. Ein Statement ist auf diese Weise immer fest mit der erzeugenden Connection verbunden. Beim Entfernen der Connection werden somit auch immer alle zugehörigen Statements entfernt.
Nachdem das Objekt der Klasse RSQL_Statement erzeugt wurde und Sie einen Zeiger auf dieses Objekt erhalten haben, können Sie das Statement ausführen oder einen Cursor darauf deklarieren. Außerdem liefert Ihnen das Objekt Informationen über die Struktur der Ein- bzw. Ausgabedaten. Hierzu dienen die Klassen RSQL_DescriptorList und RSQL_Descriptor.
Das Deklarieren eines Cursors erfolgt mit Hilfe der Methode DeclareCursor, die einen Zeiger auf ein Objekt der Klasse RSQL_Cursor liefert. Dies ist vergleichbar mit der Erzeugung eines RSQL_Statements aus einer RSQL_Connection. Einen solchen Cursor können Sie nun mittels der Methodenfunktion Open öffnen und anschließend die Daten innerhalb einer Programmschleife lesen. Hierzu dient die Funktion Fetch.
Die Daten, die Fetch liefert werden in einen Speicherbereich abgelegt, dessen Adresse Sie angeben müssen, und den Sie reservieren müssen. Dies kann entweder dynamisch erfolgen, indem Sie die Größe und Strukturbeschreibung von RSQL_Statement erfragen oder Sie definieren eine C-Struktur, die einen solchen Speicherbereich beschreibt.
Die Daten in diesem Speicherbereich sind gemäß der Konventionen für C und für den in dem PC eingesetzten Prozessor ausgelegt. Die Konvertierung zwischen diesem Format und dem auf dem HP-NonStop-System von NonStop-SQL verwendeten erfolgt automatisch durch die RSQL-Bibliothek.
Wie bereits erläutert, werden beim
Zugriff auf NonStop-SQL-Daten diese in C-konforme Datentypen auf dem
PC konvertiert. Hier finden Sie eine Aufstellung der einzelnen Typen
und wie Sie auf der PC-Seite gespeichert werden.
SQL-Datentyp |
C-Datentyp |
Bemerkung |
CHAR(n) |
char[n+1] |
mit Leerzeichen aufgefüllt und mit Null-Byte abgeschlossen |
VARCHAR(n) |
char[n+1] |
mit Null-Byte zur Längenbestimmung abgeschlossen |
SMALLINT, |
short |
mit 10scale multipliziert |
unsigned NUMERIC(1-4, scale) |
unsigned short |
mit 10scale multipliziert |
INTEGER, |
long |
mit 10scale multipliziert |
unsigned NUMERIC(5-9, scale) |
unsigned long |
mit 10scale multipliziert |
LARGEINT, |
longlong |
mit 10scale multipliziert |
REAL |
float |
Umwandlung kann nur näherungsweise erfolgen, dabei ist mit Ungenauigkeiten zu rechnen |
DOUBLE |
double |
Umwandlung kann nur näherungsweise erfolgen, dabei ist mit Ungenauigkeiten zu rechnen |
DECIMAL(n,m) |
RSQL_Decimal[n+1] |
wird als Ziffernstring gespeichert |
DATETIME |
RSQL_DateTime[n+1] |
wird als Ziffernstring gespeichert |
INTERVAL |
RSQL_Interval[n+1] |
wird als Ziffernstring gespeichert |
Nullindikator |
RSQL_NullIndType |
ist ungleich 0, wenn Nullwert vorliegt |
Für einige Datentypen stehen keine Standardtypen in C bzw. C++ zur Verfügung. Für diese existieren folgende zusätzliche Vereinbarungen:
longlong
typedef __int64
longlong;
64-bit vorzeichenbehaftete Ganzzahl
RSQL_Decimal[n]
typedef
char RSQL_Decimal;
Zeichenstring zur Aufnahme der Ziffernfolge
des SQL-Typs DECIMAL(n,m)
RSQL_DateTime[n]
typedef
char RSQL_DateTime;
Zeichenstring zur Aufnahme der Ziffernfolge
des SQL-Typs DATETIME
RSQL_Interval[n]
typedef
char RSQL_Interval;
Zeichenstring zur Aufnahme der Ziffernfolge
des SQL-Typs INTERVAL
RSQL_ NullIndType
typedef char RSQL_NullIndType;
dient zur Anzeige, ob ein Wert NULL ist. Ist ungleich 0, wenn
dies der Fall ist.
Obwohl sicherlich unerwünscht, ist es jedoch möglich, dass die Ausführung einer Funktion der RSQL-Bibliothek fehlschlägt. Für diesem Fall stehen jedoch die im folgenden beschriebenen Diagnosefunktionen zur Verfügung.
Die meisten Funktionen liefern ein Ergebnis vom Typ RSQL_OkType, um anzuzeigen, ob die Ausführung erfolgreich war oder nicht. Dieser Typ ist wie folgt definiert:
enum RSQL_OkType { RSQL_NotOk=0, RSQL_Ok=1 };
Normalerweise wird RSQL_Ok zurückgegeben, im Fehlerfall jedoch RSQL_NotOk. Wenn dies der Fall ist, so kann mit der Funktion RSQL_Error der Fehlercode ermittelt werden.
RSQL_ErrorCode RSQL_Error();
Der Fehlercode wird als 16-bit Zahl dargestellt.
typedef short RSQL_ErrorCode;
Der Fehlercode kann dabei in verschiedenen Bereichen liegen, abhängig von der Fehlerursache, z.B.
TCP/IP-Probleme
R-Enscribe-Fehler
Standardfehler
Fehler bei der Ausführung von SQL-Operationen auf dem Host
Fehler bei der Ausführung von RSQL-Funktionen
Für den letzten Fall stehen symbolische Namen für die möglichen Fehlercodes zur Verfügung:
RSQLE_NotConn
(noch)
keine Verbindung hergestellt
RSQLE_Connected
Verbindung
besteht bereits
RSQLE_NameExists
Name
eines Statements oder Cursors doppelt vorhanden
RSQLE_NameUndefined
Name
nicht definiert
RSQLE_FileNotFound
Datei
nicht gefunden
RSQLE_NotPrepared
Statement ist nicht übersetzt worden
RSQLE_NotOpen
der
Cursor ist (noch) nicht geöffnet worden
RSQLE_ExecutionFailure
allgemeiner Ausführungsfehler
RSQLE_TooManyStatements
zu
viele Statements definiert
RSQLE_TooManyCursors
zu
viele Cursor definiert
RSQLE_OutOfMemory
zu
wenig Speicher vorhanden
RSQLE_Inconsistency
allgemeine Inkonsistenz bei der Datenübertragung
RSQLE_InternalFailure
interner Fehler der Bibliothek
RSQLE_DataConversion
ein Datenelement konnte nicht
konvertiert werden
Einen Spezialfall stellt der Fehlercode 100 dar, wenn er von der SQL-Datenbank geliefert wurde. Dieser bedeutet, dass keine weiteren Daten mehr geholt werden können, da bereits alle Daten übertrgen wurden. Um diesen Fall zu überprüfen steht die Funktion RSQL_NoMoreData zur Verfügung.
int RSQL_NoMoreData();
Sie liefert 1, wenn der beschriebene Fall eingetreten ist und 0 sonst.
Meist ist es sinnvoll, eine genaue textuelle Beschreibung des Fehlers an den Programmanwender ausgeben zu können. Für diese Aufgabe existiert die Funktion RSQL_ErrorText, die einen Zeiger auf den Fehlertext liefert.
const char *RSQL_ErrorText();
Beachten Sie, dass der über den Zeiger referenzierte Speicherbereich nur vorübergehend den gültigen Fehlertext enthält. Wenn Sie diesen weiterhin zur Verfügung haben möchten, aber zwischendurch andere RSQL-Funktionen aufrufen müssen, so muss dieser Text in einen separaten Bereich kopiert werden.
Dieser Abschnitt beschreibt die Funktion und die öffentlichen Komponenten, Daten und Methoden, der von RSQL zur Verfügung gestellten C++-Klassen.
Allgemeines zu Rückgabewerten:
Die meisten Funktionen liefern einen Rückgabewert vom Typ RSQL_OkType. Dieser kann zwei Werte annehmen (s. auch Abschnitt "Fehlerbehandlung"): RSQL_Ok, falls die Funktion erfolgreich ausgeführt werden konnte, andernfalls RSQL_NotOk. Da dies bei allen Funktionen gleich ist, wird darauf im folgenden nicht weiter eingegangen.
Eine Reihe anderer Funktionen liefern als Ergebnis einen Zeigertyp. In diesem Fall bedeutet die Rückgabe eines Nullzeigers, dass die Funktion nicht erfolgreich ausgeführt werden konnte.
Objekte der Klasse RSQL_Connection dienen zur Verwaltung von Client/Server-Verbindungen zwischen dem PC und dem HP-NonStop-System.
RSQL_Connection()
Konstruktor.
Initialisiert das Objekt, stellt aber noch keine Netzwerkverbindung
her.
~RSQL_Connection()
Destruktor.
Trennt die Netzwerkverbindung und löscht alle zugehörigen
Statements und Cursor.
RSQL_OkType Connect(
const
char *hostname, short port, const char *username, const char
*password)
dient zum Herstellen einer Netzwerkverbindung.
hostname ist ein gültiger Hostname bzw. eine IP-Adresse der Form
a.b.c.d. port ist die TCP-Portnummer, die dem Server auf der
NonStop-Seite zugewiesen wurde. (s. Installation der Serverseite).
username ist ein auf dem HP-NonStop-System bekannter Benutzername.
password ist das dem Benutzer zugehörige Kennwort.
PHOST econnex
enthält
nach Herstellung der Netzwerkverbindung einen Zeiger auf die
Verwaltungsstruktur der Remote-Enscribe-Verbindung. Eine detailierte
Erläuterung des Datentyps PHOST finden Sie in der
API-Beschreibung zu R-Enscribe.
RSQL_OkType Disconnect()
Trennt
die Netzwerkverbindung und löscht alle zugehörigen
Statements und Cursor.
RSQL_OkType LoadDefines(const char
*commandOrFilename)
bewirkt die Ausführung von Befehlen
zur Modifikation der DEFINEs auf der Serverseite. commandOrFilename
kann entweder einen gültigen Befehl zur Änderung von
Defines (Add, Alter, Delete) enthalten oder den Namen einer
Guardian-Datei, die solche Befehle enthält. Andere TACL-Befehle,
die in einer solchen Datei vorkommen werden ignoriert mit Ausnahme
von OBEY (bzw. O).
RSQL_OkType BeginWork()
RSQL_OkType CommitWork()
RSQL_OkType RollbackWork()
dienen zur Transaktionskontrolle und entsprechen damit den
gleichlautenden SQL-Befehlen.
RSQL_OkType ExecImmediate(const char
*statement)
führt ein SQL-Statement direkt aus
(entspricht EXECUTE IMMEDIATE). statement enthält ein gültiges
SQL-Statement.
RSQL_Statement *Prepare(const char
*name, const char *statement)
übersetzt ein
SQL-Statement, dessen Text sich in statement und dessen Name sich in
name befindet. Der Rückgabewert ist ein Zeiger auf ein mittels
new-Operator erzeugtes Objekt vom Typ RSQL-Statement (s.u.). Wenn die
Übersetzung auf Serverseite fehlschlägt, so wird kein
Statement-Objekt angelegt und stattdessen ein Nullzeiger geliefert.
RSQL_Statement *FindStatement(const
char *name)
sucht ein Statement-Objekt innerhalb einer
Serververbindung. Es wird ein Zeiger auf dasjenige Objekt geliefert,
welches beim Prepare (s.o.) mit dem gleichen Namen übersetzt
wurde.
RSQL_Cursor *FindCursor(const char
*cursorname)
sucht ein Cursor-Objekt innerhalb einer
Serververbindung. Es wird ein Zeiger auf dasjenige Objekt geliefert,
welches beim DeclareCursor (s. Abschnitt RSQL_Statement) mit dem
gleichen Namen deklariert wurde.
Objekte der Klasse RSQL_Statement dienen zur Verwaltung von SQL-Statements, die auf der Serverseite mittels PREPARE übersetzt wurden. Beachten Sie, dass es keinen öffentlichen Konstruktor gibt. RSQL_Statement-Objekte können nur mittels der Funktion RSQL_Connection::Prepare erzeugt werden.
~RSQL_Statement()
Destruktor. Löscht gleichzeitig
alle mit dem Statement verbundenen Cursor.
RSQL_OkType Prepare(const char *statement)
übersetzt
das Statement erneut. Beachten Sie, dass der Name des Statements
nicht mehr geändert werden kann. Nach Ausruf dieser Funktion
müssen Sie jedoch gegebenenfalls vorhandene Cursor neu
deklarieren.
char *name
dient zur Ermittlung des Namens des
Statements.
int type
enthält den Typ des übersetzten
Statements. Enthält einen der in der folgenden Tabelle
gezeigten Werte, deren detailierte Erläuterung Sie in der
Dokumentation zu HP NonStop-SQL finden.
Konstante |
Statement-Typ |
_SQL_STATEMENT_SELECT |
select (cursor) statement |
_SQL_STATEMENT_INSERT |
insert statement |
_SQL_STATEMENT_UPDATE |
update statement |
_SQL_STATEMENT_DELETE |
delete statement |
_SQL_STATEMENT_DDL |
DDL statement |
_SQL_STATEMENT_CONTROL |
run-time control statement |
_SQL_STATEMENT_DCL |
lock, unlock, free resources |
_SQL_STATEMENT_GET |
get statements |
RSQL_Connection *connection
enthält einen Zeiger auf das zugehörige
RSQL_Connection-Objekt.
RSQL_DescriptorList *input
enthält einen Zeiger auf die Beschreibung der
Eingabeparameter des übersetzen Statements. (siehe hierzu auch
den Abschnitt RSQL_DescriptorList)
RSQL_DescriptorList *output
enthält einen Zeiger
auf die Beschreibung der Ausgabeparameter des übersetzen
Statements. (siehe hierzu auch den Abschnitt RSQL_DescriptorList)
RSQL_OkType Execute(const void *inbuf, void *outbuf = 0)
Führt ein übersetzes Statement auf dem Server aus.
inbuf zeigt dabei auf einen Speicherblock, der die Eingabeparameter
enthält, die gemäß der Beschreibung der
RSQL_DescriptorList *input (s.o.) aufgebaut ist. Wenn das Statement
keine Eingabeparameter besitzt, so übergeben Sie hier einen
Nullzeiger. outbuf zeigt dabei auf einen Speicherblock, der die
Ausgabeparameter aufnimmt, die gemäß der Beschreibung der
RSQL_DescriptorList *output (s.o.) konvertiert werden.
RSQL_Cursor *DeclareCursor(const char *cursorname)
deklariert einen Cursor mit dem Namen cursorname für das
übersetzte SELECT-Statement. Der Rückgabewert ist ein
Zeiger auf ein mittels new-Operator erzeugtes Objekt vom Typ
RSQL-Cursor (s.u.). Wenn die Deklaration auf Serverseite
fehlschlägt, so wird kein Cursor-Objekt angelegt und
stattdessen ein Nullzeiger geliefert.
RSQL_Cursor *FindCursor(const char *cursorname)
sucht
ein zu dem Statement bereits deklariertes Cursor-Objekt. Es wird ein
Zeiger auf dasjenige Objekt geliefert, welches beim DeclareCursor
mit dem gleichen Namen deklariert wurde.
RSQL_OkType PrintDescription(int
mode = 0, FILE *fp = 0)
gibt eine Beschreibung des übersetzen
Statements in Textform auf die mittels fp referenzierte Datei aus.
Wenn fp gleich 0 ist, so wird auf stdout ausgegeben. der Parameter
mode bestimmt das Ausgabeformat: mode=0 gibt eine detailierte,
lesbare Beschreibung aus. mode=1 druckt eine Beschreibung als
C-Quellcode.
Objekte der Klasse RSQL_Cursor dienen zur Verwaltung von SQL-Cursors, die auf der Serverseite mittels DECLARE CURSOR für ein SELECT-Statement deklariert wurden. Beachten Sie, dass es keinen öffentlichen Konstruktor gibt. RSQL_Cursor-Objekte können nur mittels der Funktion RSQL_Statement::DeclareCursor erzeugt werden.
~RSQL_Cursor()
Destruktor.
Schließt gleichzeitig den gegebenenfalls geöffneten
Cursor.
char *name
dient zur
Ermittlung des Namens des Cursors
RSQL_Statement *statement
enthält
einen Zeiger auf das zugehörige RSQL_Statement-Objekt.
RSQL_OkType Open(const void *inbuf,
int fFetchAhead = RSQL_NoFetchAhead)
öffnet den Cursor.
inbuf zeigt dabei auf einen Speicherblock, der die Eingabeparameter
enthält, die gemäß der Beschreibung der
RSQL_DescriptorList *statement->input (s.o. und Abschnitt
RSQL_Statement) aufgebaut ist. Wenn das Statement keine
Eingabeparameter besitzt, so übergeben Sie hier einen
Nullzeiger.
Der Parameter fFetchAhead bestimmt, ob bei der Übertragung der Daten bei jedem Aufruf der Funktion Fetch (s.u.) genau ein Datensatz mittels des SQL-Befehls FETCH auf der Serverseite gelesen werden soll, oder ob gleich eine größere Anzahl Datensätze geholt werden sollen, wobei dadurch der Aufwand der Datenkommunikation reduziert wird, was zu erheblichen Geschwindigkeitsvorteilen führen kann.
Wenn fFetchAhead= RSQL_NoFetchAhead, so wird jeweils nur ein Datensatz übertragen. Wenn fFetchAhead= RSQL_FetchAhead, so werden pro Datenübertragung mehrere Sätze gesendet.
Beachten Sie, dass Sie die Option RSQL_FetchAhead nicht verwenden können, wenn Sie den Cursor FOR UPDATE OF deklarieren.
OkType Fetch(void *outbuf)
liest
den nächsten Datensatz eines geöffneten Cursors. outbuf
zeigt dabei auf einen Speicherblock, der die Ausgabeparameter
aufnimmt, die gemäß der Beschreibung der
RSQL_DescriptorList *statement->output (s.o. und Abschnitt
RSQL_Statement) konvertiert werden.
RSQL_OkType Close()
schliest
den Cursor. Auch wenn es hierfür keinen entsprechenden
SQL-Befehl gibt, so werden durch diese Funktion dennoch einige
Speicherbereiche wieder freigegeben. Verwenden Sie diese Funktion,
wenn Sie mit vielen Cursors arbeiten und Speicherplatzprobleme
bekommen.
Objekte der Klasse RSQL_DescriptorList dienen der Beschreibung von Eingabe- bzw. Ausgabeparametern eines übersetzen Statements. Sie werden gewöhnlich beim Aufruf der Methodenfunktion RSQL_Statement::Prepare angelegt und stehen über die Zeiger RSQL_Statement::input bzw. RSQL_Statement::output zum Lesen zur Verfügung.
RSQL_DescriptorList enthält eine Liste der jeweiligen Parameter, die einzeln durch ihr jeweiliges RSQL_Descriptor-Objekt beschrieben werden.
RSQL_DescriptorList(int aCount, int
afOutput)
Konstruktor. Legt eine neue Liste der Länge
aCount an. afOutput ist ungleich null, wenn es sich um eine Liste von
Ausgabeparametern handelt, und gleich null, wenn es sich um
Eingabeparameter handelt.
~RSQL_DescriptorList()
Destruktor. Löscht gleichzeitig alle zugehörigen
RSQL_Descriptor-Objekte.
int Count() const
liefert die
Anzahl der enthaltenen RSQL_Descriptor-Objekte.
const RSQL_Descriptor *Descriptor(int
position) const
liefert einen Zeiger auf das
RSQL_Descriptor-Objekt an der Position position, die dabei zwischen 0
und Count()-1 liegen kann.
const RSQL_Descriptor&
operator[](int position) const
liefert eine Referenz auf das
RSQL_Descriptor-Objekt an der Position position, die dabei zwischen 0
und Count()-1 liegen kann.
size_t BufferSize() const
liefert
die Gesamtgröße in Bytes des Speicherbereichs, der
benötigt wird, um alle Parameterdaten der Liste auf der PC-Seite
speichern zu können.
RSQL_DataBuffer *AllocBuffer() const
legt einen Datenspeicherbereich in passender Größe an,
um alle Parameterdaten der Liste auf der PC-Seite speichern zu
können. Der Rückgabewert ist ein Zeiger auf ein
RSQL_DataBuffer-Objekt (s.u.).
RSQL_OkType PrintDescription(int mode
= 0, FILE *fp = 0)
gibt eine Beschreibung der Parameterliste
in Textform auf die mittels fp referenzierte Datei aus. Wenn fp
gleich 0 ist, so wird auf stdout ausgegeben. der Parameter mode
bestimmt das Ausgabeformat: mode=0 gibt eine detailierte, lesbare
Beschreibung aus. mode=1 druckt eine Beschreibung als C-Quellcode.
Objekte der Klasse RSQL_Descriptor dienen der Beschreibung einzelner Eingabe- bzw. Ausgabeparametern eines übersetzen Statements. Sie werden gewöhnlich beim Erzeugen von Objekten des Typs RSQL_DescriptorList erzeugt (s.o.).
char *name
Name des Parameters
gemäß der SQL-Anweisung
char *ind_name
Name des
Nullwert-Indikators gemäß der SQL-Anweisung. Dieser Zeiger
ist gleich 0, wenn der Parameter keine Nullwerte enthalten darf.
size_t xmit_size
Größe
des Parameters bei der Datenübertragung.
size_t xmit_offset
Offset des
Parameters innerhalb des Datenblocks bei der Datenübertragung
size_t xmit_null_offset
Offset
des Nullindikators innerhalb des Datenblocks bei der Datenübertragung
size_t alloc_size
Größe
des Speicherbereichs, der benötigt wird, um den Parameter in
C-Variable(n) zu speichern (z.B. data_size+1 bei Strings)
size_t alloc_align
erforderliche
Ausrichtung des Speicherbereichs, der benötigt wird, um den
Parameter in C-Variable(n) zu speichern.
size_t alloc_offs
Offset des
Parameters innerhalb des Speicherbereichs, wenn dieser z.B. mittels
der Funktion RSQL_DescriptorList::AllocBuffer angelegt wurde.
size_t null_offs
Offset des
Nullindikators innerhalb des Speicherbereichs, wenn dieser z.B.
mittels der Funktion RSQL_DescriptorList::AllocBuffer angelegt wurde.
short data_type
spezifiziert
den SQL-Datentyp. Dieser Wert entspricht der Codierung, wie er auch
von HP NonStop-SQL verwendet wird (s. dort). Die folgenden Konstanten
sind möglich:
Konstante |
Beschreibung |
_SQLDT_ASCII_F |
CHAR datatype |
_SQLDT_ASCII_F_UP |
CHAR datatype, UPSHIFTed |
_SQLDT_DOUBLE_F |
DOUBLE CHAR datatype |
_SQLDT_ASCII_V |
VARCHAR datatype |
_SQLDT_ASCII_V_UP |
VARCHAR datatype, UPSHIFted |
_SQLDT_DOUBLE_V |
DOUBLE VARCHAR datatype |
_SQLDT_16BIT_S |
16 bit signed binary number, |
_SQLDT_16BIT_U |
16 bit unsigned binary number, |
_SQLDT_32BIT_S |
32 bit signed binary number, |
_SQLDT_32BIT_U |
32 bit unsigned binary number, |
_SQLDT_64BIT_S |
64 bit signed binary number, |
_SQLDT_REAL |
32 bit FLOAT |
_SQLDT_DOUBLE |
64 bit FLOAT |
_SQLDT_DEC_U |
DECIMAL datatype: unsigned |
_SQLDT_DEC_LSS |
DECIMAL datatype: leading sign is separate |
_SQLDT_DEC_LSE |
DECIMAL datatype: leading sign is embedded |
_SQLDT_DEC_TSS |
DECIMAL datatype: trailing sign separate |
_SQLDT_DEC_TSE |
DECIMAL datatype: trailing sign embedded |
_SQLDT_DATETIME |
DATETIME datatype |
_SQLDT_INT_Y_Y |
INTERVAL YEAR TO YEAR |
_SQLDT_INT_MO_MO |
INTERVAL MONTH TO MONTH |
_SQLDT_INT_Y_MO |
INTERVAL YEAR TO MONTH |
_SQLDT_INT_D_D |
INTERVAL DAY TO DAY |
_SQLDT_INT_H_H |
INTERVAL HOUR TO HOUR |
_SQLDT_INT_D_H |
INTERVAL DAY TO HOUR |
_SQLDT_INT_MI_MI |
INTERVAL MINUTE TO MINUTE |
_SQLDT_INT_H_MI |
INTERVAL HOUR TO MINUTE |
_SQLDT_INT_D_MI |
INTERVAL DAY TO MINUTE |
_SQLDT_INT_S_S |
INTERVAL SECOND TO SECOND |
_SQLDT_INT_MI_S |
INTERVAL MINUTE TO SECOND |
_SQLDT_INT_H_S |
INTERVAL HOUR TO SECOND |
_SQLDT_INT_D_S |
INTERVAL DAY TO SECOND |
_SQLDT_INT_F_F |
INTERVAL FRACTION TO FRACTION |
_SQLDT_INT_S_F |
INTERVAL SECOND TO FRACTION |
_SQLDT_INT_MI_F |
INTERVAL MINUTE TO FRACTION |
_SQLDT_INT_H_F |
INTERVAL HOUR TO FRACTION |
_SQLDT_INT_D_F |
INTERVAL DAY TO FRACTION |
short data_len
Größe des Datenfeldes.
Dieser Wert entspricht dem, wie er auch von HP NonStop-SQL verwendet
wird (s. dort).
short data_scale
Scale (Nachkommastellen) des
Datenfeldes, z.B. bei Feldern des Typs NUMERIC. Dieser Wert
entspricht dem, wie er auch von HP NonStop-SQL verwendet wird (s.
dort).
short precision
Präzision (Anzahl Stellen
insgesamt) des Datenfeldes, z.B. bei Feldern des Typs NUMERIC.
Dieser Wert entspricht dem, wie er auch von HP NonStop-SQL verwendet
wird (s. dort).
RSQL_OkType PrintDescription(int mode=0, FILE *fp=0, int
preflen=0)
gibt eine Beschreibung des Parameters in Textform
auf die mittels fp referenzierte Datei aus. Wenn fp gleich 0 ist, so
wird auf stdout ausgegeben. der Parameter mode bestimmt das
Ausgabeformat: mode=0 gibt eine detailierte, lesbare Beschreibung
aus. mode=1 druckt eine Beschreibung als C-Quellcode. preflen gibt
die Länge des gemeinsamen Namenspräfix an, der nicht mit
ausgedruckt werden soll.
Objekte der Klasse RSQL_DataBuffer werden zur Verwaltung dynamisch angelegter Speicherbereiche zur Aufnahme von Parameterdaten verwendet. Sie können sowohl separat, als auch mittels der Funktion RSQL_DescriptorList::AllocBuffer erzeugt werden.
RSQL_DataBuffer(size_t aSize)
Konstruktor. Legt
Speicherbereich der Größe aSize in Bytes an.
RSQL_DataBuffer(RSQL_DescriptorList *pDescList)
Konstruktor. Legt Speicherbereich der für die angegebene
Parameterliste passenden Größe an.
~RSQL_DataBuffer()
Destruktor. Gibt den
Speicherbereich wieder frei.
size_t size
Größe des angelegten
Speicherbereiches in Bytes.
char *data
Adresse des angelegten Speicherbereiches
operator char *()
cast-Operator, liefert die Adresse
des angelegten Speicherbereiches.
#include "rsql.h" #include <stdio.h> static void pe(const char *text) { printf("%s. Error #%d\n%s\n", text, RSQL_Error(), RSQL_ErrorText() ); } int main() { RSQL_Connection NonStop; RSQL_OkType result; result = NonStop.Connect("prod01", 741, "USER.NAME", "MYPASS"); if (result != RSQL_Ok) { pe("cannot connect"); return 1; } NonStop.LoadDefines("ADD DEFINE =EMPL, FILE \ED.$DATA.SQLFILES.EMPL"); RSQL_Statement *stmt; if (0 == (stmt = NonStop.Prepare( "mystmt", "SELECT * FROM =EMPL FOR BROWSE ACCESS" ))) { pe("cannot prepare statement"); return 1; } RSQL_Cursor *crsr; if (0 == (crsr = stmt->DeclareCursor("mycrsr"))) { pe("cannot declare cursor"); return 1; } if (crsr->Open(0, RSQL_FetchAhead) == RSQL_NotOk) { pe("cannot open"); return 1; } struct mystmt_out { RSQL_Decimal EMPNUM[4+1]; char FIRST_NAME[15+1]; char LAST_NAME[20+1]; RSQL_Decimal DEPTNUM[4+1]; RSQL_Decimal JOBCODE[4+1]; unsigned long SALARY; } d; int n = 0; while (crsr->Fetch(&d) == RSQL_Ok) { printf("#%3d: %s|%s|%s|%s|%s|%10ld\n", ++n, d.EMPNUM, d.FIRST_NAME, d.LAST_NAME, d.DEPTNUM, d.JOBCODE, d.SALARY); } if (!RSQL_NoMoreData()) { pe("cannot fetch"); return 1; } // Connection ist auto-Variable, wird automatisch entfernt // dabei werden auch der Cursor und das Statement gelöscht return 0; }