本記事では、CアプリケーションがOBCIを介してOceanBaseデータベースに接続し、使用する方法について説明します。
機能の適用範囲
この内容はOceanBaseデータベースEnterprise Editionにのみ適用されます。OceanBaseデータベースCommunity EditionはMySQLモードのみ提供します。
前提条件
基本的なデータベース開発環境が設定されていることを確認してください。
以下のハードウェア環境を満たしていることを確認してください:
ハードウェアプラットフォーム:x86_64。
オペレーティングシステム:CentOS/Redhat系Linuxディストリビューション7.2。
コンパイラ:GCC 4.8。
技術サポートにお問い合わせいただき、OBCIとLibOBClientのRPMインストールパッケージを取得してください。
注意
前提条件について、以下の点にもご注意ください:
- OBCI V2.0.4以降では、RPMパッケージの
includeフォルダには、oci.hやociap.hなどのヘッダーファイルが含まれなくなりました。業務上のコンパイルに際しては、まずOracle clntsh関連のRPMをインストールし、そのヘッダーファイルを直接使用する必要があります。 - OceanBase:V2.2.76以降のバージョン(現在のバージョンの完全な機能を体験するには、OceanBaseデータベースV4.0以降のバージョンの使用を推奨します)。
- ODP(OBProxy):V4.0以降のバージョンを推奨します。
- libobclient:V2.1.1以降のバージョン。
- Oracle関連ドライバーファイル
oracle-instantclientのインストール(OBCI V2.0.4以降はOracleヘッダーファイルが必要です)。 - OBCIがインストール済みであり、事前にGCCコンパイラがデプロイされていること。
ステップ1:データベース接続文字列の取得
OceanBaseデータベースのデプロイ担当者または管理者から、該当するデータベース接続文字列を取得します。例:
obclient -h100.88.xx.xx -usys@oracle -p****** -P2881
データベース接続文字列には、データベースへのアクセスに必要なパラメータ情報が含まれています。アプリケーションを作成する前に、データベース接続文字列を使用してデータベースへのログインを検証し、接続文字列のパラメータ情報が正しいことを確認できます。
パラメータ説明:
-h:OceanBaseデータベースの接続IPアドレス。場合によってはODPのアドレスです。
-u:テナントの接続ユーザー名。形式はユーザー@テナント#クラスタ名です。Oracleモードの管理者ユーザー名はデフォルトで
sysです。データベースに直接接続する場合はクラスタ名を記入せず、ODPを介して接続する場合は記入する必要があります。-p:ユーザーパスワード。
-P:OceanBaseデータベースの接続ポート番号。ODPのリスニングポートでもあります。
ステップ2:C関連ドライバのインストール
RPMパッケージを取得したら、コマンドラインツールでrootユーザー権限を使用して以下のコマンドを実行し、OBCIドライバをインストールします:
rpm -ivh obci-<version>.x86_64.rpm
rpm -ivh libobclient-<version>.x86_64.rpm
デフォルトでは、パッケージに含まれるプログラムとファイルは以下のパスにインストールされます:
ヘッダーファイルは
/u01/obclient/includeにインストールされます。ライブラリファイルは
/u01/obclient/libにインストールされます。
ステップ3:アプリケーションの作成
本記事では、具体的な例を通じて、OceanBaseデータベースのOracleモードにおいて、CアプリケーションがOBCIを介してデータベースサーバーOBServerノードとやり取りする基本的な方法を紹介します。
OBCI環境とスレッドを初期化します。
/*OBCIプログラム環境の初期化*/ OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL) /*環境ハンドルの初期化*/ OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0)必要なハンドルとデータ構造を割り当てます。
/*サービスコンテキストハンドル*/ OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0) /*サーバーハンドル*/ OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0) /*セッションハンドル*/ OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0) /*エラーハンドル*/ OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0) /*記述子ハンドル*/ OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0)データベースへの接続を確立し、ユーザーセッションを作成します。
/*ユーザー名とパスワードの設定*/ OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strUserName, (ub4)strlen(strUserName), OCI_ATTR_USERNAME, errhp) OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strPassword, (ub4)strlen(strPassword), OCI_ATTR_PASSWORD, errhp) /*サーバー環境ハンドルの属性設定*/ OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX,(dvoid *)srvhp, (ub4)0, OCI_ATTR_SERVER, errhp) OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)authp,0, OCI_ATTR_SESSION, errhp) /*ユーザーセッションの作成と開始*/ OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT) OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0)SQLを使用してOceanBaseサーバーとデータをやり取りし、その後データ処理を行います。OBCIアプリケーションにおけるSQL文の実行手順は以下のとおりです:
関数
OCIStmtPrepare()またはOCIStmtPrepare2()を呼び出してSQL文を準備します。OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX,OCI_DEFAULT)OCIBindByPos()またはOCIBindByName()などの関数を1つまたは複数呼び出し、入力変数のアドレスをDML文のプレースホルダーにバインドします。OCIBindByPos(stmthp, &bidhp[0], errhp, 1, &szpersonid, sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0) OCIBindByName(stmthp, &bidhp[0], errhp, (const OraText*)":personid", 9, &szpersonid, sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0)OCIStmrExecute()関数を呼び出してSQL文を実行します。OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT)OCIDefineByPos()関数を呼び出して、SQL文のデータ出力項目に対応する出力変数を定義します。OCIDefineByPos(stmthp, &defhp[0], errhp, 1, &szpersonid, sizeof(szpersonid), SQLT_INT, &ind[0], 0, 0, OCI_DEFAULT)OCIStmtFetch()関数を呼び出して、クエリの結果セットを取得します。OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)
ユーザーセッションを終了し、データベースとの接続を切断します。
/*セッションの終了*/ OCISessionEnd(svchp, errhp, authp, (ub4)0) /*データベースとの接続の切断*/ OCIServerDetach(srvhp, errhp, OCI_DEFAULT)プログラムで割り当てたハンドルを解放します。
OCIHandleFree((dvoid *)dschp, OCI_HTYPE_DESCRIBE) OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT) OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR) OCIHandleFree((dvoid *)authp, OCI_HTYPE_SESSION) OCIHandleFree((dvoid *)svchp, OCI_HTYPE_SVCCTX) OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER)
サンプルコード
サンプルファイル test.c のコード内容は以下のとおりです:
/**********************************************************
* Copyright(C) 2014 - 2020 Alibaba Inc. All Rights Reserved.
*
* Filename: ob_oci_test.c
* Description: ----
* Create: 2020-07-07 10:14:59
* Last Modified: 2020-07-07 10:14:59
***********************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "oci.h"
/*ハンドル宣言*/
OCIEnv *envhp; /*環境ハンドル*/
OCISvcCtx *svchp; /*サービス環境ハンドル*/
OCIServer *srvhp; /*サーバーハンドル*/
OCISession *authp; /*セッションハンドル*/
OCIStmt *stmthp; /*ステートメントハンドル*/
OCIDescribe *dschp; /*ディスクリプタハンドル*/
OCIError *errhp; /*エラーハンドル*/
OCIDefine *defhp[3]; /*定義ハンドル*/
OCIBind *bidhp[4]; /*バインドハンドル*/
sb2 ind[3]; /*インデックサー変数*/
/*SELECT結果セットをバインドするパラメータ*/
int szpersonid; /*personid列を格納*/
text szname[51]; /*name列を格納*/
text szemail[51]; /*mail列を格納*/
char sql[256]; /*実行されるSQLステートメントを格納*/
int main(int argc, char *argv[])
{
char strServerName[50];
char strUserName[50];
char strPassword[50];
/*サーバー、ユーザー名、パスワードの設定*/
strcpy(strServerName, "172.30.xx.xx:2881");
strcpy(strUserName, "s**@oracle");
strcpy(strPassword, "******");
/*OCIアプリケーション環境の初期化*/
OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL);
/*環境ハンドルの初期化*/
OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0);
/*ハンドルの割り当て*/
OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0);
/*サーバー環境ハンドル*/
OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0);
/*サーバーハンドル*/
OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0);
/*セッションハンドル*/
OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0);
/*エラーハンドル*/
OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0);
/*ディスクリプタハンドル*/
/*サーバーへの接続*/
OCIServerAttach(srvhp, errhp, (text *)strServerName, (sb4)strlen(strServerName), OCI_DEFAULT);
/*ユーザー名とパスワードの設定*/
OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strUserName, (ub4)strlen(strUserName), OCI_ATTR_USERNAME, errhp);
OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strPassword, (ub4)strlen(strPassword), OCI_ATTR_PASSWORD, errhp);
/*サーバー環境ハンドルの属性設定*/
OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4)0, OCI_ATTR_SERVER, errhp);
OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)authp, 0, OCI_ATTR_SESSION, errhp);
/*ユーザーセッションの作成と開始*/
OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT);
OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0);
/*ステートメントハンドル*/
/************************************************************************/
/*personテーブルの作成*/
/************************************************************************/
static text* SQL_CREATE_TB = (text*)"create table person(personid number, name varchar(256), email varchar(256))";
/*SQLステートメントの準備*/
OCIStmtPrepare(stmthp, errhp, SQL_CREATE_TB, strlen((char *)SQL_CREATE_TB),OCI_NTV_SYNTAX, OCI_DEFAULT);
/*SQLステートメントの実行*/
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_DEFAULT);
/*データベースへのコミット*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*データの挿入*/
/************************************************************************/
memset(sql, 0, sizeof(sql));
strcpy(sql, "insert into person values(:personid,:name,:email)");
/*SQLステートメントの準備*/
OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql),OCI_NTV_SYNTAX, OCI_DEFAULT);
/*入力列のバインド*/
OCIBindByName(stmthp, &bidhp[0], errhp, (const OraText*)":personid", 9, &szpersonid, sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0);
OCIBindByName(stmthp, &bidhp[2], errhp, (const OraText*)":name", 5, szname, sizeof(szname), SQLT_STR, NULL, NULL, NULL, 0, NULL, 0);
OCIBindByName(stmthp, &bidhp[3], errhp, (const OraText*)":email", 6, szemail, sizeof(szemail), SQLT_STR, NULL, NULL, NULL, 0, NULL, 0);
/*入力パラメータの設定*/
szpersonid = 1;
memset(szname, 0, sizeof(szname));
strcpy((char*)szname, "obtest");
memset(szemail, 0, sizeof(szemail));
strcpy((char*)szemail, "t***@ob.com");
/*SQLステートメントの実行*/
OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT);
/*データベースへのコミット*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*personテーブルのクエリ*/
/************************************************************************/
strcpy(sql, "select personid ,name,email from person;");
/*SQLステートメントの準備*/
OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
/*出力列のバインド*/
OCIDefineByPos(stmthp, &defhp[0], errhp, 1, &szpersonid, sizeof(szpersonid), SQLT_STR, &ind[0], 0, 0, OCI_DEFAULT);
OCIDefineByPos(stmthp, &defhp[1], errhp, 2, (ub1 *)szname, sizeof(szname), SQLT_STR, &ind[1], 0, 0, OCI_DEFAULT);
OCIDefineByPos(stmthp, &defhp[2], errhp, 3, (ub1 *)szemail, sizeof(szemail), SQLT_STR, &ind[2], 0, 0, OCI_DEFAULT);
/*SQLステートメントの実行*/
OCIStmtExecute(svchp, stmthp, errhp, (ub4)0, 0, NULL, NULL,
OCI_DEFAULT);
printf("%-10s%-10s%-10s\n", "PERSONID", "NAME", "email");
while ((OCIStmtFetch(stmthp, errhp, 1, OCI FETCH_NEXT, OCI_DEFAULT)) != OCI_NO_DATA)
{
printf("%-10d", szpersonid);
printf("%-10s", szname);
printf("%-10s\n", szemail);
break;
}
/*データベースへのコミット*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*personテーブルの削除*/
/************************************************************************/
static text* SQL_DROP_TB = (text*)"drop table person";
/*SQLステートメントの準備*/
OCIStmtPrepare(stmthp, errhp, (text*)SQL_DROP_TB, strlen((char *)SQL_DROP_TB), OCI_NTV_SYNTAX, OCI_DEFAULT);
/*SQLステートメントの実行*/
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_COMMIT_ON_SUCCESS);
/*データベースへのコミット*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
//セッション終了
OCISessionEnd(svchp, errhp, authp, (ub4)0);
//データベース接続の切断
OCIServerDetach(srvhp, errhp, OCI_DEFAULT);
//OCIハンドルの解放
OCIHandleFree((dvoid *)dschp, OCI_HTYPE_DESCRIBE);
OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT);
OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR);
OCIHandleFree((dvoid *)authp, OCI_HTYPE_SESSION);
OCIHandleFree((dvoid *)svchp, OCI_HTYPE_SVCCTX);
OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER);
return 0;
}
コード内のデータベース接続パラメータを修正します。以下の項目を参照し、対応する値は手順1で取得したデータベース接続文字列から取得します。
strcpy(strServerName, "172.30.xx.xx:2881");
strcpy(strUserName, "s**@oracle");
strcpy(strPassword, "******");
strServerName:
-hと-Pパラメータから取得します。IP:portの形式です。OceanBaseデータベースの接続IPは、通常ODPアドレスと、アクセスに使用するポート番号です。strUserName:
-uパラメータから取得します。テナントの接続ユーザー名で、形式は ユーザー@テナント#クラスタ名 です。Oracleモードの管理者ユーザー名はデフォルトでsysです。データベースに直接接続する場合はクラスタ名を記入せず、ODPを介して接続する場合は記入する必要があります。strPassword:
-pパラメータから取得します。ユーザーパスワードです。
ステップ4:アプリケーションを実行する
コードの編集が完了したら、以下のコマンドでコンパイルします:
//コンパイル
gcc test.c -I/u01/obclient/include /u01/obclient/lib/libobci.a -L/usr/local/lib64 -lstdc++ -lpthread -ldl -lm -g -o test
コンパイルが完了したら、プログラムを実行します。以下のような結果が得られれば、データベースへの接続に成功し、ステートメントが正常に実行されたことを示します。
./test
PERSONID NAME email
1 obtest t***@ob.com
詳細を見る
OBCIのインストールと使用方法の詳細については、公式ドキュメントの《OceanBase C言語呼び出しインターフェース》を参照してください。