本記事では、OceanBase Connector/ODBC と OceanBase データベースを使用して、テーブルの作成、データの挿入、クエリなどの基本的な操作を実現するアプリケーションの構築方法を紹介します。
前提条件
OceanBaseデータベースをインストール済みで、Oracleモードのユーザーテナントを作成していること。OceanBaseデータベースのインストールに関する詳細は、デプロイの概要を参照してください。
Visual Studioがインストールされていること。
OceanBase Connector/ODBCドライバーがインストールされていること。
説明
OceanBase公式Webサイトのリソース > ダウンロードセンター > エンタープライズ版ページのドライバーとミドルウェアモジュールから、OceanBase ODBCドライバーWindows版のインストールパッケージをダウンロードしてください。Windows版OceanBase Connector/ODBCドライバーのインストールパッケージはワンクリックでデプロイできる形式です。デフォルトの手順に従ってインストールしてください。
手順
説明
本記事で示す操作手順は、Windows環境でVisual Studio Community 2019を使用してこのプロジェクトをコンパイルおよび実行する場合のものです。他のOS環境やコンパイラを使用する場合は、操作手順が若干異なる可能性があります。
c-oceanbase-odbcプロジェクトを開きます。c-oceanbase-odbcプロジェクトのプロパティを設定します。- OceanBaseデータベースの接続情報を取得します。
c-oceanbase-odbcプロジェクト内のデータベース接続情報を修正します。- プロジェクトをビルドします。
- アプリケーションを実行します。
- 出力結果を確認します。
ステップ1:c-oceanbase-odbcプロジェクトを開く
Visual Studio Community 2019を起動します。
既存のプロジェクトを開きます。
Visual Studio Community 2019の開始画面で、使用を開始する前に プロジェクトまたはソリューションを開く(P) ボタンをクリックします。または、Visual Studio Community 2019の開始画面で、使用を開始する前に コードなしで続行(W) ボタンをクリックするか、上部メニューバーから ファイル -> 開く -> プロジェクト/ソリューション(P) を選択します。
c-oceanbase-odbc プロジェクト フォルダに移動し、プロジェクトファイル(
c-oceanbase-odbc.slnまたはc-oceanbase-odbc.vcxproj)を選択して 開く をクリックします。
ステップ2:c-oceanbase-odbcプロジェクトのプロパティを設定する
プロジェクトのプロパティページを開きます。
ソリューションエクスプローラーで 選択したプロジェクトを右クリックし、コンテキストメニューで プロパティ を選択するか、Visual Studioの上部メニューバーで プロジェクト -> プロパティ を選択するか、ショートカットキー Alt + Enter を使用します。
設定マネージャーの設定。
プロパティページで、上部にある 設定(C) のドロップダウンメニューを選択します。ドロップダウンメニューで、Debug を選択します。
プロパティページで、上部にある プラットフォーム(P) のドロップダウンメニューを選択します。ドロップダウンメニューで、x64 を選択します。
文字セットの設定。
プロパティページで 詳細設定 タブを選択し、文字セット 項目を見つけます。ドロップダウンメニューで、マルチバイト文字セットを使用する を選択します。
ステップ3:OceanBaseデータベース接続情報を取得する
OceanBaseデータベースのデプロイ担当者または管理者から、該当するデータベース接続文字列を取得します。
例:
obclient -hxxx.xxx.xxx.xxx -P2881 -usys@oracle001 -p******
パラメータ説明:
-h:OceanBaseデータベースの接続IPアドレス。ODP接続方式ではODPアドレスを使用し、直接接続方式ではOBServerノードのIPアドレスを使用します。-P:OceanBaseデータベースの接続ポート。ODP接続方式のデフォルトポートは2883で、ODPデプロイ時にカスタマイズ可能です。直接接続方式のデフォルトポートは2881で、OceanBaseデータベースのデプロイ時にカスタマイズ可能です。-u:テナントの接続アカウント。ODP接続の一般的な形式はユーザー名@テナント名#クラスタ名またはクラスタ名:テナント名:ユーザー名です。直接接続方式の形式はユーザー名@テナント名です。-p:アカウントのパスワード。
接続文字列の詳細については、OBClientを使用してOceanBaseテナントに接続するを参照してください。
ステップ4:c-oceanbase-odbcプロジェクトのデータベース接続情報を修正する
ステップ3:OceanBaseデータベース接続情報を取得する の情報に基づき、test_tbl1.cpp ファイル内のデータベース接続情報を修正します。
例:
char* mydriver = (char*)"Driver={OceanBase ODBC 2.0 Driver};Server=xxx.xxx.xxx.xxx;Port=2881;Database=sys;User=sys@oracle001;Password=******;Option=3;";
ステップ5:プロジェクトをビルドする
ビルド メニューを選択し、ソリューションのビルド を選択します。ビルド中、コンパイラの出力およびエラーや警告情報が表示されます。
ステップ6:アプリケーションを実行する
デバッグ メニューを選択し、デバッグの開始 または 実行の開始(デバッグなし) を選択してアプリケーションを実行します。
ステップ7:出力結果を確認する
出力結果はデバッグコンソールに表示されます。プログラムの設計ロジックとコードに基づいて、出力の処理方法を判断できます。
プロジェクトコードについて
c-oceanbase-odbc をクリックして、プロジェクトコードをダウンロードします。これは、c-oceanbase-odbc.zip という名前の圧縮ファイルです。
解凍すると、c-oceanbase-odbc という名前のフォルダが作成されます。ディレクトリ構造は以下のとおりです:
c-oceanbase-odbc
├─ c-oceanbase-odbc.sln
├─ c-oceanbase-odbc.vcxproj
├─ c-oceanbase-odbc.vcxproj.filters
├─ c-oceanbase-odbc.vcxproj.user
└─ test_tbl1.cpp
ファイルの説明:
c-oceanbase-odbc.sln:Visual Studioのソリューションファイルで、1つまたは複数のプロジェクトを管理するために使用されます。c-oceanbase-odbc.vcxproj:Visual Studioのプロジェクトファイルで、C/C++プロジェクトの構造と設定を記述するために使用されます。c-oceanbase-odbc.vcxproj.filters:Visual Studioのプロジェクトフィルターファイルで、プロジェクト内のファイルのディレクトリ構造と編成方法を定義するために使用されます。c-oceanbase-odbc.vcxproj.user:ユーザー固有のプロジェクト設定を格納するファイルです。test_tbl1.cpp:データテーブルの構造を定義し、データテーブル操作を実装したソースコードファイルです。
test_tbl1.cppファイルのコード紹介
test_tbl1.cpp ファイルは、test_tbl1 という名前のデータテーブルを定義するために使用され、データテーブルの作成、データの挿入、クエリ操作を実装しています。
この test_tbl1.cpp ファイルのコードは、主に以下の部分で構成されています:
ヘッダーファイルのインポート。
ヘッダーファイル
stdio.h、assert.h、windows.h、sql.h、sqlext.hをインポートします。コード:
#include <stdio.h> #include <assert.h> #include <windows.h> #include <sql.h> #include <sqlext.h>関数
odbc_print_errorの定義。この関数の役割は、プログラムの実行中にODBC関連のエラーが発生した場合に呼び出し、エラー情報を出力することです。具体的な手順は以下のとおりです:
- 関数名を
odbc_print_errorと定義し、パラメータSQLSMALLINT HandleTypeとSQLHANDLE Handleを指定します。これらは、エラー情報に対応するハンドルタイプとハンドルを指定するために使用されます。 - ODBCから取得したエラー情報を格納する変数を定義します。これらの変数の型と名前は、ODBC APIで定義されたデータ型と名前です。
SQLGetDiagRec()を使用して、ODBCで最後に生成されたエラー情報を取得します。この関数の呼び出し後、SQLState、NativeError、SQLMessage配列にはエラー情報の関連内容が格納されます。fprintf関数を使用して、エラー情報を標準出力ストリームに出力します。[%s] (%d) %s\nは出力フォーマットであり、printf関数のフォーマット文字列に似ています。%sは文字列型データの出力に使用され、%dは整数型データの出力に使用され、\nは改行を表します。SQLState、NativeError、SQLMessageはそれぞれフォーマット文字列内の3つのパラメータに対応し、出力するエラー情報の内容を表します。
コード:
static void odbc_print_error(SQLSMALLINT HandleType, SQLHANDLE Handle) { SQLCHAR SQLState[6]; SQLINTEGER NativeError; SQLCHAR SQLMessage[SQL_MAX_MESSAGE_LENGTH] = { 0 }; SQLSMALLINT TextLengthPtr; SQLGetDiagRec(HandleType, Handle, 1, SQLState, &NativeError, SQLMessage, SQL_MAX_MESSAGE_LENGTH, &TextLengthPtr); fprintf(stdout, "[%s] (%d) %s\n", SQLState, NativeError, SQLMessage); }- 関数名を
関数
ASSERT_CHECKの定義。この関数の役割は、ODBC関数呼び出しの戻り値をチェックし、処理することです。つまり、ODBC API関数の戻り値にエラーが発生していないかをチェックし、エラーがある場合はエラー情報を出力してプログラムを終了します。具体的な手順は以下のとおりです:
- マクロ名を
ASSERT_CHECKと定義し、パラメータSQLSMALLINT HandleType、SQLHANDLE Handle、SQLRETURN rcodeを指定します。これらはそれぞれODBCハンドルタイプ、ODBCハンドル、ODBC API関数呼び出しの戻り値です。 if文を使用してODBC API関数の戻り値を判断します。戻り値がSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOと等しくない場合、関数呼び出しにエラーが発生したことを意味します。odbc_print_error関数を呼び出して、ODBCエラー情報を出力します。assert関数を呼び出して、プログラムの実行中にアサーションチェックを行います。ODBC関数呼び出しでエラーが発生した場合、プログラムは中断されます。
コード:
static void ASSERT_CHECK(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLRETURN rcode) { if (rcode != SQL_SUCCESS && rcode != SQL_SUCCESS_WITH_INFO) { odbc_print_error(HandleType, Handle); assert(0); } }- マクロ名を
関数
mainの定義。プログラムのエントリ関数
mainを定義し、整数値を返します。main関数内では、データベース接続やデータ操作に関連するコードを記述します。コード:
int main() { // 環境ハンドルの申請 // ODBCバージョンの環境プロパティの設定 // 接続ハンドルの割り当て // データソースへの接続 // テーブルの作成 // データの挿入 // データのクエリ // クリーンアップ作業、具体的なリソースハンドルの解放 }変数の定義。
変数
henvを定義します。これはODBC環境ハンドル型のオブジェクトで、ODBC接続とリソースの割り当てを管理するために使用されます。OutConnStrとOutConnStrLenは、接続文字列とその長さを格納するために使用されます。これらのパラメータは、データベースに接続する際にSQLDriverConnect関数に渡され、データベースへの正常な接続時の戻り値やその他の接続情報を取得します。コード:
HENV henv; SQLCHAR OutConnStr[255]; SQLSMALLINT OutConnStrLen;環境ハンドルの申請。
SQLAllocHandle関数を使用してODBC環境ハンドルを割り当て、ASSERT_CHECK関数を使用して割り当て結果をチェックし、割り当てが成功したことを確認します。具体的な手順は以下のとおりです:SQLAllocHandle関数の実行後、SQLRETURN型の値が返され、関数の実行結果を示します。コード内では、この戻り値はrcode変数に格納されます。SQLAllocHandle関数のパラメータは以下のとおりです:
SQL_HANDLE_ENV:割り当てるハンドルのタイプを指定します。ここではSQL_HANDLE_ENVで、環境ハンドルを割り当てることを示します。SQL_NULL_HANDLE:親ハンドルを指定します。ここではSQL_NULL_HANDLEで、親ハンドルがないことを示します。&henv:割り当てられたハンドルを格納する変数へのポインタです。ここではhenv、つまり環境ハンドルの変数です。
ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックします。rcodeがSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOでない場合、つまりハンドルの割り当てに失敗した場合、ASSERT_CHECK関数はodbc_print_error関数を呼び出してエラー情報を出力し、assertマクロを使用してプログラムの実行を終了します。
コード:
SQLRETURN rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);ODBCバージョンの環境プロパティの設定。
SQLSetEnvAttr関数を使用してODBC環境のプロパティを設定します。これにより、データベース接続とドライバーの動作に影響を与える環境レベルのプロパティを設定できます。また、ASSERT_CHECK関数を使用してプロパティ設定の結果をチェックし、設定が成功したことを確認します。具体的な手順は以下のとおりです:SQLSetEnvAttr関数の実行後、SQLRETURN型の値が返され、関数の実行結果を示します。コード内では、この戻り値はrcode変数に格納されます。SQLSetEnvAttr関数のパラメータは以下のとおりです:
henv:ODBC環境ハンドルで、プロパティを設定する環境オブジェクトを指定します。SQL_ATTR_ODBC_VERSION:設定する環境プロパティのタイプを指定します。ここではSQL_ATTR_ODBC_VERSIONで、ODBCバージョンのプロパティを設定することを示します。(void*)SQL_OV_ODBC3:プロパティ値へのポインタです。ここではSQL_OV_ODBC3で、ODBCバージョンをODBC 3.xに設定することを示します。0:プロパティ値の長さです。ここでは、プロパティ値が列挙定数であるため、長さは0です。
ASSERT_CHECK関数を使用して、SQLSetEnvAttr関数の戻り値rcodeをチェックします。rcodeがSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOでない場合、つまりプロパティの設定に失敗した場合、ASSERT_CHECK関数はodbc_print_error関数を呼び出してエラー情報を出力し、assertマクロを使用してプログラムの実行を終了します。
コード:
rcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);接続ハンドルの割り当て。
SQLAllocHandle関数を使用してODBC接続ハンドルを割り当て、ASSERT_CHECK関数を使用してハンドル割り当ての結果をチェックし、割り当てが成功したことを確認します。具体的な手順は以下のとおりです:SQLAllocHandle関数の実行後、SQLRETURN型の値が返され、関数の実行結果を示します。コード内では、この戻り値はrcode変数に格納されます。SQLAllocHandle関数のパラメータは以下のとおりです:
SQL_HANDLE_DBC:割り当てるハンドルのタイプを指定します。ここではSQL_HANDLE_DBCで、接続ハンドルを割り当てることを示します。henv:既に割り当てられたODBC環境ハンドルで、親ハンドルとして使用され、接続ハンドルと関連付けられます。&hdbc:割り当てられた接続ハンドルを格納する変数へのポインタです。
ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックします。rcodeがSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOでない場合、つまりハンドルの割り当てに失敗した場合、ASSERT_CHECK関数はodbc_print_error関数を呼び出してエラー情報を出力し、assertマクロを使用してプログラムの実行を終了します。
コード:
SQLHDBC hdbc; rcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); ASSERT_CHECK(SQL_HANDLE_DBC, hdbc, rcode);データソースへの接続。
SQLDriverConnect関数を使用して、指定されたODBCデータソースに接続します。そして、ASSERT_CHECK関数を使用して接続操作の結果をチェックし、接続が成功したことを確認します。具体的な手順は以下のとおりです:接続データベースに必要な詳細情報を記述するための接続文字列
mydriverを定義します。この文字列には以下の部分が含まれます:Driver={OceanBase ODBC 2.0 Driver}:使用するODBCドライバーをOceanBase ODBC 2.0 Driverと指定します。Server=your_ip:データベースサーバーのIPアドレスを指定します。Port=your_port:データベース接続時に使用するポート番号を指定します。Database=your_schema:接続するデータベースの名前を指定します。User=your_use:データベースに接続するために使用するユーザー名を指定します。Password=your_password:データベースに接続するために使用するパスワードを指定します。Option=3:接続オプションを指定します。値は3で、TCP/IP接続を使用することを示します。
SQLDriverConnect関数を使用して、指定されたODBCデータソースに接続します。関数の実行後、SQLRETURN型の値が返され、関数の実行結果を示します。コード内では、この戻り値はrcode変数に格納されます。この関数のパラメータは以下のとおりです:
hdbc:ODBC接続ハンドルで、データソースとの接続を確立するために使用されます。NULL:予約済みのパラメータで、使用されません。mydriver:接続文字列で、ドライバー名、データベースアドレス、ポート番号、データベース名、ユーザー名、パスワードなど、データベース接続に必要なすべての情報が含まれます。strlen((char*)mydriver) + 1:接続文字列の長さです。OutConnStr:SQLCHAR型のバッファで、接続文字列を格納するために使用されます。255:バッファの長さです。&OutConnStrLen:接続文字列の実際の長さを格納する変数へのポインタです。SQL_DRIVER_NOPROMPT:接続フラグで、接続時にプロンプトボックスを表示しないよう指示します。
ASSERT_CHECK関数を使用して、SQLDriverConnect関数の戻り値rcodeをチェックします。rcodeがSQL_SUCCESSまたはSQL_SUCCESS_WITH_INFOでない場合、つまり接続に失敗した場合、ASSERT_CHECK関数はodbc_print_error関数を呼び出してエラー情報を出力し、assertマクロを使用してプログラムの実行を終了します。
コード:
char* mydriver = (char*)"Driver={OceanBase ODBC 2.0 Driver};Server=your_ip;Port=your_port;Database=your_schema;User=your_use;Password=your_password;Option=3;"; rcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)mydriver, strlen((char*)mydriver) + 1, OutConnStr, 255, &OutConnStrLen, SQL_DRIVER_NOPROMPT); ASSERT_CHECK(SQL_HANDLE_DBC, hdbc, rcode);OceanBaseデータベースへの接続に必要なパラメータの説明:
your_ip:OceanBaseデータベースへの接続IPアドレス。ODP接続方式ではODPアドレスを使用し、直接接続方式ではOBServerノードのIPアドレスを使用します。your_port:OceanBaseデータベースへの接続ポート。ODP接続方式のデフォルトポートは2883で、ODPデプロイ時にカスタマイズ可能です。直接接続方式のデフォルトポートは2881で、OceanBaseデータベースのデプロイ時にカスタマイズ可能です。your_schema:アクセスするSchema名です。your_user:テナントの接続アカウント。ODP接続方式の形式:ユーザー名@テナント名#クラスタ名またはクラスタ名:テナント名:ユーザー名。直接接続方式の形式:ユーザー名@テナント名。your_password:アカウントのパスワード。
テーブルの作成。
SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当て、次にSQLExecDirect関数を使用してSQLステートメントを実行し、テーブルを作成します。コードではASSERT_CHECK関数も使用して、ハンドルの割り当てとステートメントの実行の結果をチェックし、操作が成功したことを確認します。最後に、SQLFreeHandle関数を使用してステートメントハンドルを解放し、リソースを解放します。具体的な手順は以下のとおりです:ODBCステートメントハンドル
stmtを宣言します。SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当てます。ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックし、ハンドルの割り当てが成功したことを確認します。SQLExecDirect関数を使用してSQLステートメントを実行します。ここではCREATE TABLEステートメントを実行し、test_tbl1という名前のテーブルを作成します。ASSERT_CHECK関数を使用して、SQLExecDirect関数の戻り値rcodeをチェックし、ステートメントの実行が成功したことを確認します。SQLFreeHandle関数を使用してODBCステートメントハンドルを解放します。
コード:
SQLHSTMT stmt; rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); rcode = SQLExecDirect(stmt, (SQLCHAR*)"CREATE TABLE test_tbl1(id NUMBER PRIMARY KEY, name VARCHAR2(50),age NUMBER NOT NULL)", SQL_NTS); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); SQLFreeHandle(SQL_HANDLE_STMT, stmt);データの挿入。
SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当て、次にSQLExecDirect関数を使用してSQLステートメントを実行し、データベーステーブルにデータを挿入します。コードではASSERT_CHECK関数も使用して、ハンドルの割り当てとステートメントの実行の結果をチェックし、操作が成功したことを確認します。最後に、SQLFreeHandle関数を使用してステートメントハンドルを解放し、リソースを解放します。具体的な手順は以下のとおりです:SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当てます。ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックし、ハンドルの割り当てが成功したことを確認します。SQLExecDirect関数を使用してSQLステートメントを実行します。ここではINSERT INTOステートメントを実行し、test_tbl1テーブルに3行のレコードを挿入します。ASSERT_CHECK関数を使用して、SQLExecDirect関数の戻り値rcodeをチェックし、ステートメントの実行が成功したことを確認します。SQLFreeHandle関数を使用してODBCステートメントハンドルを解放します。
コード:
rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); rcode = SQLExecDirect(stmt, (SQLCHAR*)"INSERT INTO test_tbl1 (id,name,age) VALUES (1,'Tom', 18),(2,'Jerry', 20),(3,'Bob', 22)", SQL_NTS); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); SQLFreeHandle(SQL_HANDLE_STMT, stmt);データのクエリ。
SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当て、次にSQLExecDirect関数を使用してSQLステートメントを実行し、結果セットを取得します。その後、SQLBindCol関数を使用して結果セットの列を変数にバインドし、SQLFetch関数を使用して結果セットを行ごとに取得します。whileループ内で、rcodeの値に基づいて結果セットのデータを出力します。最後に、SQLFreeHandle関数を使用してステートメントハンドルを解放し、リソースを解放します。具体的な手順は以下のとおりです:SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当てます。ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックし、ハンドルの割り当てが成功したことを確認します。SQLExecDirect関数を使用してSQLステートメントを実行します。ここではSELECTステートメントを実行し、test_tbl1テーブルからすべての行を取得します。ASSERT_CHECK関数を使用して、SQLExecDirect関数の戻り値rcodeをチェックし、ステートメントの実行が成功したことを確認します。SQLLEN型の変数resを宣言し、列バインド操作の結果を格納します。SQLINTEGER型の変数idとageを宣言し、結果セットの対応する列の値を格納します。SQLCHAR型の配列nameを宣言し、結果セットの対応する列の値を格納します。SQLBindCol関数を使用して、結果セットの最初の列を変数idにバインドします。SQLBindCol関数を使用して、結果セットの2番目の列を配列nameにバインドします。SQLBindCol関数を使用して、結果セットの3番目の列を変数ageにバインドします。SQLFetch関数を使用して結果セットの行を取得し、行内のデータをバインドされた変数に格納します。whileループは、すべての行が取得されるまで繰り返し実行されます。whileループ内で、rcodeの値を判断し、対応する行のデータを出力します。rcodeがSQL_ERRORの場合は、エラー情報を出力します。SQLFreeHandle関数を使用してODBCステートメントハンドルを解放します。
コード:
rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); rcode = SQLExecDirect(stmt, (SQLCHAR*)"SELECT * FROM test_tbl1", SQL_NTS); ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode); SQLLEN res = SQL_NTS; SQLINTEGER id, age; SQLCHAR name[255]; SQLBindCol(stmt, 1, SQL_C_SLONG, &id, sizeof(id), &res); SQLBindCol(stmt, 2, SQL_C_CHAR, name, sizeof(name), &res); SQLBindCol(stmt, 3, SQL_C_SLONG, &age, sizeof(age), &res); while ((rcode = SQLFetch(stmt)) != SQL_NO_DATA_FOUND) { if (rcode == SQL_ERROR) { printf("sql error!\n"); } else { printf("id:%d, name:%s, age:%ld\n", id, name, age); } } SQLFreeHandle(SQL_HANDLE_STMT, stmt);最後に、具体的なリソースハンドルを解放するためのクリーンアップ作業を行います。
データベースとの接続を切断し、関連するODBCハンドルと環境ハンドルを解放してリソースを開放します。SQLDisconnect 関数と SQLFreeHandle 関数を呼び出すことで、プログラムはデータベースとの接続を適切に閉じ、関連するハンドルを解放できます。最後に、0を返すことでプログラムが正常に実行されたことを示します。具体的な手順は以下のとおりです:
1. SQLDisconnect 関数を使用してデータベースとの接続を切断します。
2. SQLFreeHandle 関数を使用してデータベース接続ハンドルを解放します。
3. SQLFreeHandle 関数を使用してODBC環境ハンドルを解放します。
4. 0を返して、プログラムが正常に実行されたことを示します。
**コード:**
```c
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
```
全コード表示
#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
static void odbc_print_error(SQLSMALLINT HandleType, SQLHANDLE Handle)
{
SQLCHAR SQLState[6];
SQLINTEGER NativeError;
SQLCHAR SQLMessage[SQL_MAX_MESSAGE_LENGTH] = { 0 };
SQLSMALLINT TextLengthPtr;
SQLGetDiagRec(HandleType, Handle, 1, SQLState, &NativeError, SQLMessage, SQL_MAX_MESSAGE_LENGTH, &TextLengthPtr);
fprintf(stdout, "[%s] (%d) %s\n", SQLState, NativeError, SQLMessage);
}
static void ASSERT_CHECK(SQLSMALLINT HandleType, SQLHANDLE Handle, SQLRETURN rcode)
{
if (rcode != SQL_SUCCESS && rcode != SQL_SUCCESS_WITH_INFO) {
odbc_print_error(HandleType, Handle);
assert(0);
}
}
int main()
{
HENV henv;
SQLCHAR OutConnStr[255];
SQLSMALLINT OutConnStrLen;
SQLRETURN rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);
rcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);
SQLHDBC hdbc;
rcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
ASSERT_CHECK(SQL_HANDLE_DBC, hdbc, rcode);
char* mydriver = (char*)"Driver={OceanBase ODBC 2.0 Driver};Server=your_ip;Port=your_port;Database=your_schema;User=your_use;Password=your_password;Option=3;";
rcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR*)mydriver, strlen((char*)mydriver) + 1, OutConnStr, 255, &OutConnStrLen, SQL_DRIVER_NOPROMPT);
ASSERT_CHECK(SQL_HANDLE_DBC, hdbc, rcode);
SQLHSTMT stmt;
rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
rcode = SQLExecDirect(stmt, (SQLCHAR*)"CREATE TABLE test_tbl1(id NUMBER PRIMARY KEY, name VARCHAR2(50),age NUMBER NOT NULL)", SQL_NTS);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
rcode = SQLExecDirect(stmt, (SQLCHAR*)"INSERT INTO test_tbl1 (id,name,age) VALUES (1,'Tom', 18),(2,'Jerry', 20),(3,'Bob', 22)", SQL_NTS);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
rcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &stmt);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
rcode = SQLExecDirect(stmt, (SQLCHAR*)"SELECT * FROM test_tbl1", SQL_NTS);
ASSERT_CHECK(SQL_HANDLE_STMT, stmt, rcode);
SQLLEN res = SQL_NTS;
SQLINTEGER id, age;
SQLCHAR name[255];
SQLBindCol(stmt, 1, SQL_C_SLONG, &id, sizeof(id), &res);
SQLBindCol(stmt, 2, SQL_C_CHAR, name, sizeof(name), &res);
SQLBindCol(stmt, 3, SQL_C_SLONG, &age, sizeof(age), &res);
while ((rcode = SQLFetch(stmt)) != SQL_NO_DATA_FOUND)
{
if (rcode == SQL_ERROR) {
printf("sql error!\n");
}
else {
printf("id:%d, name:%s, age:%ld\n", id, name, age);
}
}
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
関連ドキュメント
OceanBaseデータベースへの接続方法の詳細については、接続方法の概要を参照してください。
OceanBase Connector/ODBCの詳細については、OceanBase Connector/ODBCを参照してください。
c-oceanbase-odbc サンプルプロジェクトをダウンロード