This topic describes how to connect a C application to OceanBase Database by using OBCI.
Applicability
This topic applies only to OceanBase Database Enterprise Edition. OceanBase Database Community Edition does not support this feature.
Prerequisites
Ensure that the basic database development environment is set up.
Ensure that the following hardware environment is met:
Hardware platform: x86_64.
Operating system: CentOS/Red Hat Linux 7.2.
Compiler: GCC 4.8.
Contact technical support to obtain the RPM installation packages of OBCI and LibOBClient.
Notice
Prerequisites also include the following items:
- Starting from OBCI V2.0.4, the
includefolder in the RPM package no longer contains header files such asoci.handociap.h. To compile your business code, you must first install the Oracle clntsh-related RPM package and directly use its header files. - OceanBase Database: V2.2.76 or later (we recommend that you use OceanBase Database V4.0 or later to experience all the features of the current version).
- OBProxy: V4.0 or later.
- libobclient: V2.1.1 or later.
- Install the
oracle-instantclientdriver file (starting from OBCI V2.0.4, the Oracle header files are required). - OBCI is installed and the GCC compiler is deployed.
Step 1: Obtain the database connection string
Contact the OceanBase deployment engineer or administrator to obtain the corresponding database connection string. For example:
obclient -h100.88.xx.xx -usys@oracle -p****** -P2881
The database connection string contains the parameters required to access the database. Before creating an application, you can use the database connection string to log in to the database and verify that the parameters in the connection string are correct.
Parameter description:
-h: the IP address for connecting to the OceanBase database. This is sometimes an ODP address.
-u: the username for connecting to the tenant. The format is username@tenant name#cluster name. In Oracle mode, the default username for the tenant administrator is
sys. If you connect directly to the database, you do not need to specify the cluster name. If you connect through an ODP, you must specify the cluster name.-p: the user password.
-P: the port for connecting to the OceanBase database, which is also the listening port of the ODP.
Step 2: Install the C driver
After you obtain the RPM package, run the following commands in the CLI as the root user to install the OBCI driver:
rpm -ivh obci-<version>.x86_64.rpm
rpm -ivh libobclient-<version>.x86_64.rpm
By default, the programs and files in the software package are installed in the following paths:
Header files are installed in the
/u01/obclient/includedirectory.Library files are installed in the
/u01/obclient/libdirectory.
Step 3: Write an application
This topic describes how to use an application to interact with an OBServer node in Oracle mode of OceanBase Database by using OBCI.
Initialize the OBCI environment and thread.
/*Initialize the OBCI environment.*/ OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL) /*Initialize the environment handle.*/ OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0)Allocate the necessary handles and data structures.
/*Service context handle.*/ OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0) /*Server handle.*/ OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0) /*Session handle.*/ OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0) /*Error handle.*/ OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0) /*Describe handle.*/ OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0)Connect to the database and create a user session.
/*Set the username and password.*/ 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) /*Set the server environment handle attribute.*/ 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) /*Create and start a user session.*/ OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT) OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0)Exchange data with OceanBase Database by using SQL statements and process the data. The execution of an SQL statement in an OBCI application is as follows:
Call the
OCIStmtPrepare()orOCIStmtPrepare2()function to prepare the SQL statement.OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX,OCI_DEFAULT)Call one or more functions, such as
OCIBindByPos()orOCIBindByName(), to bind the addresses of input variables to placeholders in the DML statement.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)Call the
OCIStmrExecute()function to execute the SQL statement.OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT)Call the
OCIDefineByPos()function to define output variables for the data output items in the SQL statement.OCIDefineByPos(stmthp, &defhp[0], errhp, 1, &szpersonid, sizeof(szpersonid), SQLT_INT, &ind[0], 0, 0, OCI_DEFAULT)Call the
OCIStmtFetch()function to obtain the result set of the query.OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)
End the user session and disconnect from the database.
/*End the session.*/ OCISessionEnd(svchp, errhp, authp, (ub4)0) /*Disconnect from the database.*/ OCIServerDetach(srvhp, errhp, OCI_DEFAULT)Release the handles allocated in the program.
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)
Sample code
The code in the test.c file is as follows:
/**********************************************************
* 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"
/*Declare handles.*/
OCIEnv *envhp; /*Environment handle.*/
OCISvcCtx *svchp; /*Service context handle.*/
OCIServer *srvhp; /*Server handle.*/
OCISession *authp; /*Session handle.*/
OCIStmt *stmthp; /*Statement handle.*/
OCIDescribe *dschp; /*Describe handle.*/
OCIError *errhp; /*Error handle.*/
OCIDefine *defhp[3]; /*Define handle.*/
OCIBind *bidhp[4]; /*Bind handle.*/
sb2 ind[3]; /*Indicator variable.*/
/*Bind the result set of the SELECT statement.*/
int szpersonid; /*Stores the personid column.*/
text szname[51]; /*Stores the name column.*/
text szemail[51]; /*Stores the mail column.*/
char sql[256]; /*Stores the executed SQL statement.*/
int main(int argc, char *argv[])
{
char strServerName[50];
char strUserName[50];
char strPassword[50];
/*Set the server, username, and password.*/
strcpy(strServerName, "172.30.xx.xx:2881");
strcpy(strUserName, "s**@oracle");
strcpy(strPassword, "******");
/*Initialize the OCI application environment.*/
OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL);
/*Initialize the environment handle.*/
OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0);
/*Allocate handles.*/
OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0);
/*Server context handle.*/
OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0);
/*Server handle.*/
OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0);
/*Session handle.*/
OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0);
/*Error handle.*/
OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0);
/*Descriptor handle.*/
/*Connect to the server.*/
OCIServerAttach(srvhp, errhp, (text *)strServerName, (sb4)strlen(strServerName), OCI_DEFAULT);
/*Set the username and password.*/
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);
/*Set the server context handle attribute.*/
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);
/*Create and start a user session.*/
OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT);
OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0);
/*Statement handle.*/
/************************************************************************/
/*Create the person table.*/
/************************************************************************/
static text* SQL_CREATE_TB = (text*)"create table person(personid number, name varchar(256), email varchar(256))";
/*Prepare the SQL statement.*/
OCIStmtPrepare(stmthp, errhp, SQL_CREATE_TB, strlen((char *)SQL_CREATE_TB),OCI_NTV_SYNTAX, OCI_DEFAULT);
/*Execute the SQL statement.*/
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_DEFAULT);
/*Commit to the database.*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*Insert data*/
/************************************************************************/
memset(sql, 0, sizeof(sql));
strcpy(sql, "insert into person values(:personid,:name,:email)");
/*Prepare the SQL statement*/
OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql),OCI_NTV_SYNTAX, OCI_DEFAULT);
/*Bind the input columns*/
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);
/*Set the input parameters*/
szpersonid = 1;
memset(szname, 0, sizeof(szname));
strcpy((char*)szname, "obtest");
memset(szemail, 0, sizeof(szemail));
strcpy((char*)szemail, "t***@ob.com");
/*Execute the SQL statement*/
OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT);
/*Commit to the database*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*Query the person table*/
/************************************************************************/
strcpy(sql, "select personid ,name,email from person;");
/*Prepare the SQL statement*/
OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
/*Bind the output columns*/
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);
/*Execute the SQL statement*/
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;
}
/*Commit to the database*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
/************************************************************************/
/*Drop the person table*/
/************************************************************************/
static text* SQL_DROP_TB = (text*)"drop table person";
/*Prepare the SQL statement*/
OCIStmtPrepare(stmthp, errhp, (text*)SQL_DROP_TB, strlen((char *)SQL_DROP_TB), OCI_NTV_SYNTAX, OCI_DEFAULT);
/*Execute the SQL statement*/
OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_COMMIT_ON_SUCCESS);
/*Commit to the database*/
OCITransCommit(svchp, errhp, OCI_DEFAULT);
//End the session
OCISessionEnd(svchp, errhp, authp, (ub4)0);
//Disconnect from the database
OCIServerDetach(srvhp, errhp, OCI_DEFAULT);
//Release the OCI handles
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;
}
Modify the database connection parameters in the code. For more information, see the following fields. The values of the fields are obtained from the database connection string obtained in step 1.
strcpy(strServerName, "172.30.xx.xx:2881");
strcpy(strUserName, "s**@oracle");
strcpy(strPassword, "******");
strServerName: the value obtained from the
-hand-Pparameters in the format ofIP:port. The IP address of the OceanBase Database server, which is usually an ODP address, and the port number for access.strUserName: The username for connecting to the tenant, in the format username@tenant name#cluster name. The username is specified by the
-uparameter. In Oracle mode, the default username for the administrator issys. If you connect directly to the database, you do not need to specify the cluster name. If you connect through ODP, you need to specify the cluster name.strPassword: The password for the user, specified by the
-pparameter.
Step 4: Run the application
After you complete the code editing, run the following command to compile the code:
// Compile
gcc test.c -I/u01/obclient/include /u01/obclient/lib/libobci.a -L/usr/local/lib64 -lstdc++ -lpthread -ldl -lm -g -o test
After the compilation is complete, run the application and obtain the following result, which indicates that the database connection is successful and the statement is executed properly:
./test
PERSONID NAME email
1 obtest t***@ob.com
