ODBC-Programmierung per API
Willemers Informatik-Ecke

Header-Dateien

Ein Modul, das ODBC-Aufrufe macht, braucht die Headerdateien sql.h, sqlext.h und in einigen Fällen sqltypes.h.

Funktionen zum An- und Abmelden

SQLAllocHandle und SQLFreeHandle

SQLRETURN SQLAllocHandle(
     SQLSMALLINT HandleTyp, 
     SQLHANDLE  InHandle, 
     SQLHANDLE *OutHandle); 

SQLRETURN SQLFreeHandle(   
     SQLSMALLINT HandleTyp, 
     SQLHANDLE FreeHandle); 

HandleTyp
Der HandleTyp ist einer der folgenden:

SQL_HANDLE_ENV Ein Environmenthandle wird gesucht
SQL_HANDLE_DBC Es wird ein Verbindungshandle angelegt
SQL_HANDLE_STMT
SQL_HANDLE_DESC

InHandle
Das InHandle ist das Handle, das als Basis gebraucht wird, um ein neues Handle zu erlangen.
Wenn HandleTyp SQL_HANDLE_ENV ist, braucht man kein InHandle und der Parameter wird mit SQL_NULL_HANDLE belegt. Ist HandleType SQL_HANDLE_DBC, wird das Environment-Handle übergeben. Ist HandleTyp SQL_HANDLE_STMT oder SQL_HANDLE_DESC wird das Verbindungs-Handle gebraucht.
OutHandle
Hier wird die Adresse der Variablen übergeben, die das Handle aufnehmen soll.
FreeHandle
Das Handle, das freigegeben werden soll.

Bemerkung

Die Funktion SQLAllocHandle löst in der Version 3 die Funktionen SQLAllocConnect, SQLAllocEnv und SQLAllocStmt ab. Die Funktion SQLFreeHandle löst in der Version 3 die Funktionen SQLFreeConnect, SQLFreeEnv und SQLFreeStmt ab.

SQLConnect

SQLRETURN SQLConnect(
     HDBC hDBC,
     UCHAR *strDSN,
     SWORD lenDSN,
     UCHAR *strUSER,
     SWORD lenUSER,
     UCHAR *strPASSWD,
     SWORD lenPASSWD);

hDBC
Das Handle
strDSN
Der Name der Datenquelle
lenDSN
Die Länge des Namen der Datenquelle. SQL_NTS gibt an, dass der String nullterminiert ist
strUSER
Benutzerkennung
lenUSER
Die Länge der Benutzerkennung. SQL_NTS gibt an, dass der String nullterminiert ist
strPASSWD
Das Kennwort
lenPASSWD
Die Länge des Kennworts. SQL_NTS gibt an, dass der String nullterminiert ist
Verbindet mit einer Datenquelle.

Beispiel

HENV hEnv;
HDBC hDBC;

  SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);  
  SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
  SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDBC);
  if (hDBC) {
    retCode = SQLConnect(hDBC, (UCHAR *)"testdb", SQL_NTS, 
                         (UCHAR *)"adm",SQL_NTS,(UCHAR *)"adm",SQL_NTS);
    ...
    SQLDisconnect(hDBC);
    SQLFreeHandle(SQL_HANDLE_DBC, hDBC);
  }
  SQLFreeHandle(SQL_HANDLE_ENV, hEnv);

Funktionen zur Ausführung von Anweisungen

Für die Ausführung von Anweisungen wird ein Handle benötigt, das durch SQLAllocHandle und SQLFreeHandle angelegt und freigegeben wird.

HDBC hDBC;
HSTMT hStmt;

SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt)
. . .
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);

SQLPrepare, SQLExecute und SQLExecDirect

Eine Anweisung wird mit SQLPrepare zunächst übersetzt. Der Statementhandle hält dann diese Anweisung, die durch den Aufruf von SQLExecute auch mehrmalig ausgeführt werden kann.

SQLRETURN SQLPrepare(   
     SQLHSTMT StatementHandle, 
     SQLCHAR * StatementText, 
     SQLINTEGER TextLength); 

SQLRETURN SQLExecute(
     SQLHSTMT     StatementHandle);

Wird die Anweisung nur einmal ausgeführt, kann man beides in SQLExecDirect zusammenfassen.

SQLRETURN SQLExecDirect(   
     SQLHSTMT StatementHandle, 
     SQLCHAR * StatementText, 
     SQLINTEGER TextLength); 

StatementHandle
Das Handle des Kommandos
StatementText
Die SQL-Anweisung
TextLength
Die Länge der SQL-Anweisung

SQLEndTran

SQLRETURN SQLEndTran(   
     SQLSMALLINT HandleType, 
     SQLHANDLE Handle, 
     SQLSMALLINT CompletionType); 

HandleType
SQL_HANDLE_ENV oder SQL_HANDLE_DBC.
Handle
Das Handle (Env oder DBC)
CompletionType
Je nach Absicht:
SQL_COMMIT um die Trasaktion abzuschliessen und durchzuführen.
SQL_ROLLBACK um auf den Zustand der letzten Transaktion zurückzugehen.

Bemerkung

Löst in der Version 3 die Funktion SQLTransact ab.

Das Auslesen: SQLBindCol und SQLFetch

Das Auslesen der Daten geschieht in drei Schritten. Zunächst wird der SQL-SELECT-Befehl abgesetzt, um die Ergebnismenge zu beschreiben. Dies kann beispielsweise mit SQLExecDirect erfolgen.

Dann wird festgelegt, welche Spalten interessieren. Es wird bei dieser Gelegenheit angegeben, in welchen Speicher die Daten gelangen sollen. Zu diesem Zweck wird SQLBindCol verwendet. Es bindet eine Spalte an einen Datenpuffer.

Schliesslich wird Zeile für Zeile mit dem Befehl SQLFetch die Ergebnismenge des SQL-Befehls in den Datenspeicher geholt.

SQLRETURN SQLBindCol(   
     SQLHSTMT StatementHandle, 
     SQLUSMALLINT ColumnNumber, 
     SQLSMALLINT TargetType, 
     SQLPOINTER TargetValuePtr, 
     SQLINTEGER BufferLength, 
     SQLINTEGER * StrLen_or_IndPtr); 

StatementHandle
Das Statement Handle
ColumnNumber
Die Spaltennummer beginnt bei 1. Nur wenn Bookmarks verwendet werden, was durch SQL_ATTR_USE_BOOKMARKS angegeben wird, gibt es eine Spalte 0, die die Bookmarkspalte darstellt.
TargetType
Der Datentyp des Puffers, in den geladen werden soll. Die Angabe der entsprechenden Konstanten führt zu einer Umwandlung der Datenbankinhalte in den angegeben Typ.
TargetValuePtr
Zeiger auf den Datenpuffer, in dem die Daten erwartet werden. Ist dieser Wert 0, wird der Spaltenpuffer von der Spalte gelöst und nicht mehr verwendet.
BufferLength
Grösse des Puffers in Bytes.
StrLen_or_IndPtr
gibt die Länge der gelieferten Daten an oder:
SQL_NO_TOTAL
SQL_NULL_DATA

Liefert als Rügabewert SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_ERROR, oder SQL_INVALID_HANDLE.

HENV hEnv;	// das Handle des Environment
HDBC hDBC;	// das Handle der Datenbank
HSTMT hStmt;	// das Handle fuer die Anweisung
RETCODE retCode;
char strPerformer[1024];
char strTitle[1024];
long len;
	...
	retCode = SQLAllocHandle(SQL_HANDLE_STMT, hDBC, &hStmt);
	if (retCode==SQL_SUCCESS || retCode==SQL_SUCCESS_WITH_INFO) {
		retCode = SQLExecDirect(hStmt, (UCHAR*)"SELECT Performer,Titel FROM Song", SQL_NTS);
		if (retCode==SQL_SUCCESS || retCode==SQL_SUCCESS_WITH_INFO) {
			SQLBindCol(hStmt, 1, SQL_C_CHAR, strPerformer, 1024, &len);
			SQLBindCol(hStmt, 2, SQL_C_CHAR, strTitle, 1024, &len);
			while (1) {
				retCode = SQLFetch(hStmt);
				if (retCode==SQL_SUCCESS || retCode==SQL_SUCCESS_WITH_INFO) {
					MessageBox(hWnd, strTitle, strPerformer, MB_OK);
				}else {
					break;
				}
			}
		} else {
			MessageBox(hWnd,"ExecDirect failed", "bad", MB_OK);
		}
		SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
	}else{
		MessageBox(hWnd,"Statement failed", "bad", MB_OK);
	}