This topic describes how to use OceanBase Connector/ODBC and OceanBase Cloud to build an application for basic database operations, such as table creation, data insertion, and data query.
Download the c-oceanbase-odbc sample project Prerequisites
You have registered an OceanBase Cloud account, and created a cluster instance and an Oracle-compatible tenant in OceanBase Cloud. For more information, see Create a cluster instance and Create a tenant.
You have obtained the connection string of the Oracle-compatible tenant. For more information, see Obtain the connection string.
You have installed Visual Studio.
You have installed the OceanBase Connector/ODBC driver.
Note
You can download the installation package of OceanBase Connector/ODBC for Windows from [OceanBase Download Center](https://en.oceanbase.com/softwarecenter-cloud). Follow the default instructions to install OceanBase Connector/ODBC for Windows.
Procedure
Note
The steps provided in this topic are for compiling and running the project by using Visual Studio Community 2019 in Windows. If you use another operating system or compiler, the procedure can be slightly different.
Step 1: Open the c-oceanbase-odbc project
Start Visual Studio Community 2019.
Open an existing project.
In the start window of Visual Studio Community 2019, click Open a project or solution (P) under Get started. Alternatively, click Continue without code (W) in the lower right corner, and choose File > Open > Project/Solution (P) in the menu bar of the page that appears.
Browse to the c-oceanbase-odbc folder, select the project file c-oceanbase-odbc.sln or c-oceanbase-odbc.vcxproj, and click Open.
Step 2: Configure the properties for the c-oceanbase-odbc project
Go to the property page of the project.
Right-click the selected project in Solution Explorer and choose Properties from the menu, choose Project > Properties from the top menu bar, or use the keyboard shortcut Alt + Enter.
Configure manager settings.
On the property page, select Debug from the Configuration drop-down list.
On the property page, select x64 from the Platform drop-down list.
Set the character set.
Click the Advanced tab and find the Character Set field. Select Use Multi-Byte Character Set from the drop-down list.
Step 3: Modify the database connection information in the c-oceanbase-odbc project
Modify the database connection information in the test_tbl1.cpp file based on the obtained connection string mentioned in the "Prerequisites" section.
Here is an example:
char* mydriver = (char*)"Driver={OceanBase ODBC 2.0 Driver};Server=t5******.********.oceanbase.cloud;Port=3306;Database=sys;User=test_user;Password=******;Option=3;";
Step 4: Build the project
Choose Build > Build Solution. The output of the compiler and errors or warning messages if any are displayed during the build process.
Step 5: Run the application
Choose Debug > Start Debugging or choose Debug > Start Without Debugging to run the application.
Step 6: Check the output
The output is displayed in the debug console. You can determine how to handle the output based on the design logic and code of the application.
Project code
Click here to download the project code, which is a package named c-oceanbase-odbc.zip.
Decompress the package to obtain a folder named c-oceanbase-odbc. The directory structure is as follows:
c-oceanbase-odbc
├─ c-oceanbase-odbc.sln
├─ c-oceanbase-odbc.vcxproj
├─ c-oceanbase-odbc.vcxproj.filters
├─ c-oceanbase-odbc.vcxproj.user
└─ test_tbl1.cpp
The files and directories are described as follows:
c-oceanbase-odbc.sln: the solution file in Visual Studio that manages one or more projects.c-oceanbase-odbc.vcxproj: the project file in Visual Studio that describes the structure and configuration of a C/C++ project.c-oceanbase-odbc.vcxproj.filters: the project filter file in Visual Studio that defines the directory structure and organization of files in the project.c-oceanbase-odbc.vcxproj.user: the file that stores user-specific project settings.test_tbl1.cpp: the source code file that defines a data table and implements data table operations.
Code in test_tbl1.cpp
The test_tbl1.cpp file defines and creates a data table named test_tbl1 and implements the operations to insert data into and query data from the table.
Perform the following steps to configure the test_tbl1.cpp file:
Reference header files.
Reference header files
stdio.h,assert.h,windows.h,sql.h, andsqlext.h.The sample code is as follows:
#include <stdio.h> #include <assert.h> #include <windows.h> #include <sql.h> #include <sqlext.h>Define the
odbc_print_errorfunction.This function is called to print error messages for ODBC-related errors that occur during the running process of the application. Perform the following steps:
- Set the function name to
odbc_print_error. Specify the parametersSQLSMALLINT HandleTypeandSQLHANDLE Handleto indicate the handle type and handle corresponding to an error message. - Define the variables that store error messages obtained from ODBC. The types and names of these variables are defined in the ODBC API.
- Call
SQLGetDiagRec()to get the last generated error message in ODBC. TheSQLState,NativeError, andSQLMessagearrays then store the relevant content of the error message. - Call the
fprintffunction to print the error message to the standard output stream.[%s] (%d) %s\nis the print format, which uses a formatted string similar to that in theprintffunction.%sis used to print data of the string type,%dis used to print integer data, and\nrepresents a line break.SQLState,NativeError, andSQLMessagecorrespond to the three parameters in the formatted string, and provide the content of the error message to print.
The sample code is as follows:
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); }- Set the function name to
Define the
ASSERT_CHECKfunction.This function is used to check and process the return value of an ODBC function call. It checks whether the return value of the ODBC API function has an error, and prints the error message and exits the application if an error is present. Perform the following steps:
- Set the macro name to
ASSERT_CHECK. Specify the parametersSQLSMALLINT HandleType,SQLHANDLE Handle, andSQLRETURN rcodeto indicate the ODBC handle type, the ODBC handle, and the return value of an ODBC API function call, respectively. - Use the
ifstatement to judge the return value of an ODBC API function. If the return value is not equal toSQL_SUCCESSorSQL_SUCCESS_WITH_INFO, an error occurs in the function call. - Call the
odbc_print_errorfunction to print the ODBC error message. - Call the
assertfunction during the running of the application. When an error occurs in an ODBC function call,assertaborts the application.
The sample code is as follows:
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); } }- Set the macro name to
Define the
mainfunction.Define the entry function
mainfor the application and return an integer value. In themainfunction, write the code related to database connections and data operations.The sample code is as follows:
int main() { // Apply for an environment handle. // Set the version (an environment attribute) of ODBC. // Allocate a connection handle. // Connect to the data source. // Create a table. // Insert data. // Query data. // Release resource handles. }Define variables.
Define the
henvvariable, which is an ODBC environment handle object that manages ODBC connections and resource allocation.OutConnStrandOutConnStrLenstore the connection string and the string length respectively. These parameters are passed to theSQLDriverConnectfunction when the application connects to the database to obtain the return value and some other connection information.The sample code is as follows:
HENV henv; SQLCHAR OutConnStr[255]; SQLSMALLINT OutConnStrLen;Apply for an environment handle.
Call the
SQLAllocHandlefunction to allocate an ODBC environment handle, and call theASSERT_CHECKfunction to check the allocation result. Perform the following steps:After the
SQLAllocHandlefunction is executed, return a value of theSQLRETURNtype to indicate the execution result. Store the return value in thercodevariable. The parameters of theSQLAllocHandlefunction are as follows:SQL_HANDLE_ENV: the type of handle to be allocated. In this example, it is set toSQL_HANDLE_ENV, indicating that an environment handle is to be allocated.SQL_NULL_HANDLE: the parent handle. In this example, it is set toSQL_NULL_HANDLE, indicating that no parent handle is used.&henv: a pointer to the variable that stores the allocated handle. In this example, it is the pointer to thehenvvariable that stores the environment handle.
Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLAllocHandlefunction. If thercodevalue is notSQL_SUCCESSorSQL_SUCCESS_WITH_INFO, handle allocation fails, and theASSERT_CHECKfunction calls theodbc_print_errorfunction to print the error message and uses theassertmacro to terminate the application.
The sample code is as follows:
SQLRETURN rcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);Set the version (an environment attribute) of ODBC.
Call the
SQLSetEnvAttrfunction to set the environment attributes of ODBC to influence the behavior of the database connection and the driver. Call theASSERT_CHECKfunction to check the attribute setting result. Perform the following steps:After the
SQLSetEnvAttrfunction is executed, return a value of theSQLRETURNtype to indicate the execution result. Store the return value in thercodevariable. The parameters of theSQLSetEnvAttrfunction are as follows:henv: the ODBC environment handle that specifies the environment object for which the attribute is set.SQL_ATTR_ODBC_VERSION: the type of the environment attribute to be set. In this example, it is set toSQL_ATTR_ODBC_VERSION, indicating that the ODBC version is to be set.(void*)SQL_OV_ODBC3: a pointer to the attribute value. In this example, it is set toSQL_OV_ODBC3, indicating that the new ODBC version is ODBC V3.x.0: the length of the attribute value. In this example, the attribute value is an enumerated constant, and therefore the length is set to0.
Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLSetEnvAttrfunction. If thercodevalue is notSQL_SUCCESSorSQL_SUCCESS_WITH_INFO, attribute setting fails, and theASSERT_CHECKfunction calls theodbc_print_errorfunction to print the error message and uses theassertmacro to terminate the application.
The sample code is as follows:
rcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); ASSERT_CHECK(SQL_HANDLE_ENV, henv, rcode);Allocate a connection handle.
Call the
SQLAllocHandlefunction to allocate an ODBC connection handle, and call theASSERT_CHECKfunction to check the allocation result. Perform the following steps:After the
SQLAllocHandlefunction is executed, return a value of theSQLRETURNtype to indicate the execution result. Store the return value in thercodevariable. The parameters of theSQLAllocHandlefunction are as follows:SQL_HANDLE_DBC: the type of handle to be allocated. In this example, it is set toSQL_HANDLE_DBC, indicating a connection handle.henv: the allocated ODBC environment handle that acts as a parent handle to associate with the connection handle.&hdbc: the pointer to the variable that stores the allocated connection handle.
Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLAllocHandlefunction. If thercodevalue is notSQL_SUCCESSorSQL_SUCCESS_WITH_INFO, handle allocation fails, and theASSERT_CHECKfunction calls theodbc_print_errorfunction to print the error message and uses the assertmacroto terminate the application.
The sample code is as follows:
SQLHDBC hdbc; rcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc); ASSERT_CHECK(SQL_HANDLE_DBC, hdbc, rcode);Connect to the data source.
Call the
SQLDriverConnectfunction to connect to the specified ODBC data source. Call theASSERT_CHECKfunction to check the connection result. Perform the following steps:Define the connection string
mydriverthat describes the information required to connect to the database. The string contains the following parts:Driver={OceanBase ODBC 2.0 Driver}: specifies thatOceanBase ODBC 2.0 Driveris used as the driver.Server=your_ip: the URL for connecting to the database.Port=your_port: the port number for connecting to the database.Database=your_schema: the name of the database to connect to.User=your_use: the username used to connect to the database.Password=your_password: the password used to connect to the database.Option=3: the connection option, which is set to3, indicating a TCP/IP connection.
Call the
SQLDriverConnectfunction to connect to the specified ODBC data source. Return a value of theSQLRETURNtype after the function is executed to indicate the execution result. Store this return value in thercodevariable. The parameters of the function are as follows:hdbc: the ODBC connection handle for establishing a connection with the data source.NULL: a reserved parameter, which is not used.mydriver: the connection string that contains all the information needed to connect to the database, such as the driver name, database IP address, port number, database name, username, and password.strlen((char*)mydriver) + 1: the length of the connection string.OutConnStr: a buffer of theSQLCHARtype that stores the connection string.255: the length of the buffer.&OutConnStrLen: the pointer to the variable that stores the actual length of the connection string.SQL_DRIVER_NOPROMPT: a connection flag that specifies not to display any prompt for the connection.
Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLDriverConnectfunction. If thercodevalue is notSQL_SUCCESSorSQL_SUCCESS_WITH_INFO, the connection fails, and theASSERT_CHECKfunction calls theodbc_print_errorfunction to print the error message and uses theassertmacro to terminate the application.
The sample code is as follows:
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);The following parameters are required to connect to OceanBase Cloud:
your_ip: the access address of OceanBase Cloud. The value is sourced from the-hparameter in the connection string.your_user: the account name. The value is sourced from the-uparameter in the connection string.your_password: the account password. The value is sourced from the-pparameter in the connection string.your_schema: the name of the database to be accessed. The value is sourced from the-Dparameter in the connection string.your_port: the access port of OceanBase Cloud. The value is sourced from the-Pparameter in the connection string.
Create a table.
Call the
SQLAllocHandlefunction to allocate an ODBC statement handle, and then call theSQLExecDirectfunction to execute an SQL statement to create a table. Use theASSERT_CHECKfunction to check the results of handle allocation and statement execution. Call theSQLFreeHandlefunction to release the statement handle to free resources. Perform the following steps:Declare an ODBC statement handle
stmt.Call the
SQLAllocHandlefunction to allocate an ODBC statement handle.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLAllocHandlefunction.Call the
SQLExecDirectfunction to execute an SQL statement. Here, execute theCREATE TABLEstatement to create a table namedtest_tbl1.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLExecDirectfunction.Call the
SQLFreeHandlefunction to release the ODBC statement handle.
The sample code is as follows:
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);Insert data.
Call the
SQLAllocHandlefunction to allocate an ODBC statement handle, and then call theSQLExecDirectfunction to execute an SQL statement to insert data into a database table. Use theASSERT_CHECKfunction to check the results of handle allocation and statement execution. Call theSQLFreeHandlefunction to release the statement handle to free resources. Perform the following steps:Call the
SQLAllocHandlefunction to allocate an ODBC statement handle.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLAllocHandlefunction.Call the
SQLExecDirectfunction to execute an SQL statement. Here, execute theINSERT INTOstatement to insert three records into thetest_tbl1table.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLExecDirectfunction.Call the
SQLFreeHandlefunction to release the ODBC statement handle.
The sample code is as follows:
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);Query data.
Call the
SQLAllocHandlefunction to allocate an ODBC statement handle, and then call theSQLExecDirectfunction to execute an SQL statement to obtain the result set. Call theSQLBindColfunction to bind the columns of the result set to variables, and then call theSQLFetchfunction to get the result set row by row. In thewhileloop, print the data in the result set based on the value ofrcode. Call theSQLFreeHandlefunction to release the statement handle to free resources. Perform the following steps:Call the
SQLAllocHandlefunction to allocate an ODBC statement handle.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLAllocHandlefunction.Call the
SQLExecDirectfunction to execute an SQL statement. Here, execute theSELECTstatement that retrieves all rows from thetest_tbl1table.Call the
ASSERT_CHECKfunction to check thercodevalue returned by theSQLExecDirectfunction.Declare the
resvariable of theSQLLENtype to store the result of the column binding operation.Declare the
idandagevariables of theSQLINTEGERtype to store the values of the corresponding columns in the result set.Declare the
namearray of theSQLCHARtype to store the values of the corresponding column in the result set.Call the
SQLBindColfunction to bind the first column in the result set to theidvariable.Call the
SQLBindColfunction to bind the second column in the result set to thenamearray.Call the
SQLBindColfunction to bind the third column in the result set to theagevariable.Call the
SQLFetchfunction to get the rows in the result set and save data in the rows to the bound variables. Thewhileloop iterates until all rows are fetched.In the
whileloop, print the data of the corresponding row based on the value ofrcode. If thercodevalue isSQL_ERROR, print an error message.Call the
SQLFreeHandlefunction to release the ODBC statement handle.
The sample code is as follows:
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);Disconnect from the database and release resource handles.
Close the database connection, and release the ODBC connection handle and environment handle to free resources. Call the
SQLDisconnectandSQLFreeHandlefunctions to correctly close the connection to the database and release relevant handles. Return0to indicate that the program execution is successful. Perform the following steps:Call the
SQLDisconnectfunction to disconnect from the database.Call the
SQLFreeHandlefunction to release the ODBC connection handle.Call the
SQLFreeHandlefunction to release the ODBC environment handle.Return
0to indicate that the application execution is successful.
The sample code is as follows:
SQLDisconnect(hdbc); SQLFreeHandle(SQL_HANDLE_DBC, hdbc); SQLFreeHandle(SQL_HANDLE_ENV, henv); return 0;
Complete code
#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;
}
References
For more information about OceanBase Connector/ODBC, see OceanBase Connector/ODBC.