本記事では、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:アクセスするスキーマ名です。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関数を使用して結果セットを1行ずつ取得します。whileループ内で、rcodeの値に基づいて結果セット内のデータを出力します。最後に、SQLFreeHandle関数を使用してステートメントハンドルを解放し、リソースを解放します。具体的な手順は以下のとおりです:SQLAllocHandle関数を使用してODBCステートメントハンドルを割り当てます。ASSERT_CHECK関数を使用して、SQLAllocHandle関数の戻り値rcodeをチェックし、ハンドルが正常に割り当てられたことを確認します。SQLExecDirect関数を使用してSQLステートメントを実行します。ここでは、SELECTステートメントを実行し、test_tbl1テーブルからすべての行を取得します。ASSERT_CHECK関数を使用して、SQLExecDirect関数の戻り値rcodeをチェックし、ステートメントが正常に実行されたことを確認します。SQLLEN型の変数resを宣言し、列バインド操作の結果を格納します。SQLINTEGER型の変数idとageを2つ宣言し、結果セットの対応する列の値を格納します。SQLCHAR型の配列nameを宣言し、結果セットの対応する列の値を格納します。SQLBindCol関数を使用して、結果セットの1列目を変数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を返すことでプログラムの実行が成功したことを示します。具体的な手順は以下のとおりです:
SQLDisconnect 関数を使用して、データベースへの接続を切断します。
SQLFreeHandle 関数を使用して、データベース接続ハンドルを解放します。
SQLFreeHandle 関数を使用して、ODBC環境ハンドルを解放します。
0を返し、プログラムの実行が成功したことを示します。
コード:
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を参照してください。