虚谷 ODBC 开发手册
📄字数 11.4K
👁️阅读量 加载中...
ODBC(Open Database Connectivity)是由微软制定的一套标准化数据库访问接口,允许应用程序通过统一的 API 连接和操作不同类型的数据库,无需针对特定数据库编写专用代码。虚谷 ODBC 遵循 ODBC 3.0 规范设计并开发,实现了 ODBC 应用程序对虚谷数据库的操作。
官方文档:https://learn.microsoft.com/zh-cn/sql/odbc/microsoft-open-database-connectivity-odbc
一、开发环境搭建
1.1 获取软件包
XuguDB 提供两种 XuguDB-ODBC 驱动的下载方式:产品包或单独获取。
1.1.1 产品包获取
XuguDB-ODBC 驱动压缩包在虚谷数据库的产品包内,解压产品包后,XuguDB-ODBC 驱动路径为:Driver/ODBC。不同操作系统和 CPU 架构的 XuguDB-ODBC 驱动,需要通过下载不同的产品包获取。
1.1.2 单独获取
我们提供在线下载链接,可以获取最新试用版和稳定版本的 XuguDB-ODBC 驱动。
| 操作系统 | CPU | 下载地址 |
|---|---|---|
| Windows | x86, 64-bit | 下载 |
| Linux | x86, 64-bit | 下载 |
| Linux | ARM, 64-bit | 下载 |
提示
- Windows 版本建议在 Windows 10 及以上系统使用。
- Linux 版本可以在所有对应的 CPU 架构的类 Unix 系统下运行。
- 如果有在其它系统上使用虚谷 XuguDB-ODBC 驱动的需求,请联系虚谷。
1.2 配置数据源
1.2.1 Windows
- 进入 ODBC 目录,右键 install.exe,点击以管理员身份运行;
- 运行 odbcad32 或点击 控制面板 > 管理工具 > ODBC数据源;
- 点击系统 DSN > 添加 > 选择数据源 XuguSQL > 完成;
- 输入连接参数,点击测试并成功连接数据库;
- 点击确定按钮。
1.2.2 Linux
- 安装 unixODBC
- 执行命令
odbcinst -j查看 ODBC 数据源的配置文件位置 - 将如下内容追加进 odbcinst.ini
ini
[XuguSQL]
Description=Xugu ODBC driver for linux
Driver=/your/odbc/path/libxgodbc.so
UsageCount=1- 将如下内容追加进 odbc.ini
ini
[xugu]
Description=ODBC data source for Xugu
Driver=XuguSQL
Server=127.0.0.1
Port=5138
Database=SYSTEM
User=SYSDBA
UseSSL=false
AutoCommit=true
StrictCommit=false
RetSchema=false
RetCursorId=false
RetRowId=false
UserServerCursor=false
LobRet=true
RecvIsAsyn=true
CacheFOCR=true
CharSet=utf8
TimeZone=GMT+08:00
IsoLevel=read committed
LockTimeout=60000
SubthreadRows=2000- 执行
odbcinst -q -d查看驱动信息 - 执行
odbcinst -q -s查看数据源信息 - 执行
isql xugu SYSDBA SYSDBA连接数据库
提示
虚谷 ODBC 支持与数据库进行数据加密传输,连接属性为 UseSSL,其值为 true 即为开启。在 Windows 的 ODBC 数据源管理程序中勾选“启用安全连接”即可开启数据的加密传输。
1.3 编译
1.3.1 Visual Studio
- 项目属性 -> 配置属性 -> 高级 -> 字符集,选择"使用多字节字符集"
- 在源码头部添加如下必备头文件:
C
#include <Windows.h>
#include <sql.h>
#include <sqlext.h>- 生成项目
1.3.2 gcc
- 在源码头部添加如下必备头文件:
C
#include <sql.h>
#include <sqlext.h>- 使用如下命令编译:
BASH
gcc demo.c -lodbc二、快速入门
此章节将使用最简单的代码展示如何使用 ODBC 向虚谷数据库插入和查询数据,以及展示如何通过 ODBC 操作数值类型、字符类型和结构体类型的字段以实现数值的插入和查询。
2.1 创表
使用 xgconsole 或其他管理工具连接虚谷数据库实例,在 SYSTEM 库中创建此章节所依赖的表。建表语句如下:
SQL
CREATE TABLE tab_test (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(20),
created DATE
);2.2 认识句柄
在此章节中将使用四个句柄,分别是:环境句柄、连接句柄和语句句柄。它们所对应的类型常量为:
- SQL_HANDLE_ENV
- SQL_HANDLE_DBC
- SQL_HANDLE_STMT
2.3 创建句柄
句柄的创建依赖于其它已成功创建的句柄,依赖关系为:
- SQL_HANDLE_ENV 没有依赖的句柄
- SQL_HANDLE_DBC 依赖于 SQL_HANDLE_ENV
- SQL_HANDLE_STMT 依赖于 SQL_HANDLE_DBC
创建句柄所使用的接口原型为:
C
SQLRETURN SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE *OutputHandle);其中,第一个参数为待创建的句柄类型,第二个参数为被依赖的句柄,第三个参数为待创建的句柄。创建成功则返回 SQL_SUCCESS。因此创建句柄的代码为:
C
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
//创建环境句柄
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
//创建连接句柄
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
//创建语句句柄
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);需要注意的是,创建连接句柄前需设置 ODBC 版本,创建语句句柄前需成功连接数据库。
2.4 连接数据库
连接虚谷数据库至少需要五个信息,分别为:数据库服务端的 IP、数据库服务端的端口、连接的库名、用户名和密码。连接数据库的接口原型为:
C
SQLRETURN SQLConnect(SQLHDBC ConnectionHandle,
SQLCHAR *ServerName, SQLSMALLINT NameLength1,
SQLCHAR *UserName, SQLSMALLINT NameLength2,
SQLCHAR *Authentication, SQLSMALLINT NameLength3);其中,第一个参数为连接句柄,第二个参数为数据源名称,第四个参数为用户名,第六个参数为密码。第三五七个参数为长度,可传入 SQL_NTS。连接成功则返回 SQL_SUCCESS,若连接失败可使用 SQLGetDiagRec 获取错误码以及错误信息。
C
SQLRETURN ret;
ret = SQLConnect(hdbc, "xugu", SQL_NTS, "SYSDBA", SQL_NTS, "SYSDBA", SQL_NTS);
if (ret != SQL_SUCCESS)
{
SQLCHAR sqlState[20] = {0};
SQLINTEGER nativeErr = 0;
SQLCHAR errMsg[200] = {0};
SQLSMALLINT len;
SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, sqlState, &nativeErr, errMsg, 200, &len);
printf("[%s][%d]%s\n", sqlState, nativeErr, errMsg);
}2.5 执行 SQL 语句
当连接建立成功后,即可向数据库服务端发送待执行的 SQL 语句。所使用的接口原型为:
C
SQLRETURN SQLExecDirect(SQLHSTMT StatementHandle, SQLCHAR* StatementText, SQLINTEGER TextLength);其中,第一个参数为语句句柄,第二个参数为 SQL 语句,第三个参数为 SQL 语句的长度。执行成功则返回 SQL_SUCCESS,若执行失败可使用 SQLGetDiagRec 获取错误码以及错误信息。
若执行查询,则需将变量绑定至各个列,通过 fetch 将当前行的值写入绑定的变量中。代码为:
C
int id;
char name[20];
SQL_DATE_STRUCT date;
SQLLEN len[3] = { 0 };
SQLBindCol(hstmt, 1, SQL_C_LONG, &id, 4, &len[0]);
SQLBindCol(hstmt, 2, SQL_C_CHAR, name, 20, &len[1]);
SQLBindCol(hstmt, 3, SQL_C_DATE, &date, sizeof(date), &len[2]);
ret = SQLExecDirect(hstmt, "SELECT id, name, created FROM tab_test", SQL_NTS);
while ((ret = SQLFetch(hstmt)) == SQL_SUCCESS)
printf("%d, %s, %04d-%02d-%02d\n", id, name, date.year, date.month, date.day);2.6 销毁句柄
每个句柄均存储相关的信息,因此句柄使用完毕后需将其销毁以释放内存,其接口原型为:
C
SQLRETURN SQLFreeHandle(SQLSMALLINT HandleType, SQLHANDLE Handle);其中,参数为待销毁的句柄。
C
SQLFreeHandle(hstmt);
SQLFreeHandle(hdbc);
SQLFreeHandle(henv);2.7 完整代码
C
//main.c
#ifdef _WIN32
#include <Windows.h>
#endif
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
void printError(SQLHANDLE handle, SQLSMALLINT type);
void insert(SQLHDBC hdbc);
void query(SQLHDBC hdbc);
int main()
{
SQLHENV henv;
SQLHDBC hdbc;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
ret = SQLConnect(hdbc, "xugu", SQL_NTS, "SYSDBA", SQL_NTS, "SYSDBA", SQL_NTS);
if (ret != SQL_SUCCESS)
{
printError(hdbc, SQL_HANDLE_DBC);
goto _end;
}
insert(hdbc);
query(hdbc);
SQLDisconnect(hdbc);
_end:
SQLFreeHandle(SQL_HANDLE_ENV, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return ret;
}
void printError(SQLHANDLE handle, SQLSMALLINT type)
{
SQLCHAR sqlState[20] = {0};
SQLINTEGER nativeErr = 0;
SQLCHAR errMsg[200] = {0};
SQLSMALLINT len;
SQLGetDiagRec(type, handle, 1, sqlState, &nativeErr, errMsg, 200, &len);
printf("[%s][%d]%s\n", sqlState, nativeErr, errMsg);
}
void insert(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
SQLCHAR* sql = "INSERT INTO tab_test values(1, 'Tom', '2000-01-01')";
ret = SQLExecDirect(hstmt, sql, SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
void query(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
int id = 0;
char name[20] = { 0 };
SQL_DATE_STRUCT date = { 0 };
SQLLEN len[3] = { 0 };
SQLBindCol(hstmt, 1, SQL_C_LONG, &id, 4, &len[0]);
SQLBindCol(hstmt, 2, SQL_C_CHAR, name, 20, &len[1]);
SQLBindCol(hstmt, 3, SQL_C_DATE, &date, sizeof(date), &len[2]);
ret = SQLExecDirect(hstmt, "SELECT id, name, created FROM tab_test", SQL_NTS);
while ((ret = SQLFetch(hstmt)) == SQL_SUCCESS)
printf("%d, %s, %04d-%02d-%02d\n", id, name, date.year, date.month, date.day);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}三、接口参考
3.1 数据类型
ODBC 在发送数据时需将 C 语言中的值类型转换为数据库中的值类型。在参数绑定时,需要指定被绑定变量值的类型,还需指定对应列的类型,但两种类型并非需要严格对应,部分类型间可完成数值类型转换。
3.1.1 C 语言类型
下表列出了 C 数据类型的有效类型标识符。 该表还列出了对应于每个标识符的 ODBC C 数据类型以及此数据类型的定义。
| C 类型标识符 | ODBC C typedef | C 类型 |
|---|---|---|
| SQL_C_TINYINT | SQLCHAR | char |
| SQL_C_STINYINT | SQLSCHAR | char |
| SQL_C_UTINYINT | SQLCHAR | unsigned char |
| SQL_C_SHORT | SQLSMALLINT | short int |
| SQL_C_SSHORT | SQLSMALLINT | short int |
| SQL_C_USHORT | SQLUSMALLINT | unsigned short int |
| SQL_C_LONG | SQLINTEGER | long int |
| SQL_C_SLONG | SQLINTEGER | long int |
| SQL_C_ULONG | SQLUINTEGER | unsigned long int |
| SQL_C_SBIGINT | SQLBIGINT | int64 |
| SQL_C_UBIGINT | SQLUBIGINT | unsigned int64 |
| SQL_C_FLOAT | SQLREAL | float |
| SQL_C_DOUBLE | SQLDOUBLE、SQLFLOAT | double |
| SQL_C_CHAR | SQLCHAR * | unsigned char * |
| SQL_C_BINARY | SQLCHAR * | unsigned char * |
| SQL_C_DATE | SQL_DATE_STRUCT | SQL_DATE_STRUCT |
| SQL_C_TIME | SQL_TIME_STRUCT | SQL_TIME_STRUCT |
| SQL_C_TIMESTAMP | SQL_TIMESTAMP_STRUCT | SQL_TIMESTAMP_STRUCT |
3.1.2 SQL 类型
下表为 SQL 数据类型的对应的 SQL 类型标识符。
| SQL 数据 | SQL 类型标识符 |
|---|---|
| TINYINT | SQL_TINYINT |
| SMALLINT | SQL_SMALLINT |
| INTEGER | SQL_INTEGER |
| BIGINT | SQL_BIGINT |
| REAL | SQL_REAL |
| DOUBLE | SQL_FLOAT |
| DOUBLE | SQL_DOUBLE |
| CHAR(n) | SQL_CHAR |
| VARCHAR(n) | SQL_VARCHAR |
| BINARY(n) | SQL_BINARY |
| DECIMAL(p, s) | SQL_DECIMAL |
| NUMERIC(p, s) | SQL_NUMERIC |
| DATE | SQL_TYPE_DATE |
| TIME | SQL_TYPE_TIME |
| DATETIME | SQL_TYPE_TIMESTAMP |
| TIMESTAMP | SQL_TYPE_TIMESTAMP |
3.2 API 接口
接口用法,请参考官方文档:https://learn.microsoft.com/zh-cn/sql/odbc/reference/syntax/odbc-api-reference
| 接口 | 支持 | 备注 |
|---|---|---|
| SQLAllocConnect | ✔ | 已弃用 |
| SQLAllocEnv | ✔ | 已弃用 |
| SQLAllocHandle | ✔ | |
| SQLAllocStmt | ✔ | 已弃用 |
| SQLBindCol | ✔ | |
| SQLBindParameter | ✔ | |
| SQLBrowseConnect | ✔ | |
| SQLBulkOperations | ❌ | |
| SQLCancel | ✔ | |
| SQLCancelHandle | ✔ | |
| SQLCloseCursor | ✔ | |
| SQLColAttribute | ✔ | |
| SQLColAttributes | ✔ | 已弃用 |
| SQLColumnPrivileges | ✔ | |
| SQLColumns | ✔ | |
| SQLCompleteAsync | ❌ | |
| SQLConnect | ✔ | |
| SQLCopyDesc | ✔ | |
| SQLDataSources | ✔ | |
| SQLDescribeCol | ✔ | |
| SQLDescribeParam | ✔ | |
| SQLDisconnect | ✔ | |
| SQLDriverConnect | ✔ | |
| SQLDrivers | ✔ | |
| SQLEndTran | ✔ | |
| SQLError | ✔ | 已弃用 |
| SQLExecDirect | ✔ | |
| SQLExecute | ✔ | |
| SQLExtendedFetch | ✔ | 已弃用 |
| SQLFetch | ✔ | |
| SQLFetchScroll | ✔ | |
| SQLForeignKeys | ✔ | |
| SQLFreeConnect | ✔ | 已弃用 |
| SQLFreeEnv | ✔ | 已弃用 |
| SQLFreeHandle | ✔ | |
| SQLFreeStmt | ✔ | 已弃用 |
| SQLGetConnectAttr | ✔ | |
| SQLGetConnectOption | ✔ | 已弃用 |
| SQLGetCursorName | ✔ | |
| SQLGetData | ✔ | |
| SQLGetDescField | ✔ | |
| SQLGetDescRec | ✔ | |
| SQLGetDiagField | ✔ | |
| SQLGetDiagRec | ✔ | |
| SQLGetEnvAttr | ✔ | |
| SQLGetFunctions | ✔ | |
| SQLGetInfo | ✔ | |
| SQLGetStmtAttr | ✔ | |
| SQLGetStmtOption | ✔ | 已弃用 |
| SQLGetTypeInfo | ✔ | |
| SQLMoreResults | ✔ | |
| SQLNativeSql | ✔ | |
| SQLNumParams | ✔ | |
| SQLNumResultCols | ✔ | |
| SQLParamData | ✔ | |
| SQLParamOptions | ✔ | 已弃用 |
| SQLPrepare | ✔ | |
| SQLPrimaryKeys | ✔ | |
| SQLProcedureColumns | ✔ | |
| SQLProcedures | ✔ | |
| SQLPutData | ✔ | |
| SQLRowCount | ✔ | |
| SQLSetConnectAttr | ✔ | |
| SQLSetConnectOption | ✔ | 已弃用 |
| SQLSetCursorName | ✔ | |
| SQLSetDescField | ✔ | |
| SQLSetDescRec | ✔ | |
| SQLSetEnvAttr | ✔ | |
| SQLSetParam | ✔ | 已弃用 |
| SQLSetPos | ✔ | Operation 仅支持 SQL_POSITION,LockType 未使用 |
| SQLSetScrollOptions | ✔ | 已弃用 |
| SQLSetStmtAttr | ✔ | |
| SQLSetStmtOption | ✔ | 已弃用 |
| SQLSpecialColumns | ✔ | |
| SQLStatistics | ✔ | |
| SQLTablePrivileges | ✔ | |
| SQLTables | ✔ | |
| SQLTransact | ✔ | 已弃用 |
四、示例
4.1 连接的建立与释放
C
#ifdef _WIN32
#include <Windows.h>
#endif
#include <stdio.h>
#include <sql.h>
#include <sqlext.h>
void printError(SQLHANDLE handle, SQLSMALLINT type)
{
SQLCHAR sqlState[20] = {0};
SQLINTEGER nativeErr = 0;
SQLCHAR errMsg[200] = {0};
SQLSMALLINT len;
SQLGetDiagRec(type, handle, 1, sqlState, &nativeErr, errMsg, 200, &len);
printf("[%s][%d]%s\n", sqlState, nativeErr, errMsg);
}
int main()
{
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
ret = SQLConnect(hdbc, "xugu", SQL_NTS, "SYSDBA", SQL_NTS, "SYSDBA", SQL_NTS);
if (ret != SQL_SUCCESS)
{
printError(hdbc, SQL_HANDLE_DBC);
goto _end;
}
// insert(hdbc);
// query(hdbc);
// procedure(hdbc);
// function(hdbc);
// insertLob(hdbc);
// queryLob(hdbc);
SQLDisconnect(hdbc);
_end:
SQLFreeHandle(SQL_HANDLE_ENV, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}4.2 参数绑定
C
void insert(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
ret = SQLPrepare(hstmt, "INSERT INTO tab_test(id, name, created) VALUES(?, ?, ?)", SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
int id = 1;
char name[20] = "Tom";
SQL_DATE_STRUCT date = {2000, 1, 1};
SQLLEN len[3] = { 0 };// 0 取数据实际长度,-1 为 null
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &id, 4, &len[0]);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, name, 20, &len[1]);
SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_DATE, SQL_DATE, 0, 0, &date, sizeof(date), &len[2]);
ret = SQLExecute(hstmt);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}4.3 数据查询
示例 1:SQLBindCol
C
void query(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
int id;
char name[20];
SQL_DATE_STRUCT date;
SQLLEN len[3] = { 0 };
SQLBindCol(hstmt, 1, SQL_C_LONG, &id, 0, &len[0]);
SQLBindCol(hstmt, 2, SQL_C_CHAR, name, 20, &len[1]);
SQLBindCol(hstmt, 3, SQL_C_DATE, &date, 0, &len[2]);
ret = SQLExecDirect(hstmt, "SELECT id, name, created FROM tab_test", SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
while (SQLFetch(hstmt) == SQL_SUCCESS)
{
printf(len[0] != -1 ? "%d, " : "%s, ", len[0] != -1 ? id : "null");
printf("%s, ", len[1] != -1 ? name : "null");
if (len[2] != -1)
printf("%04d-%02d-%02d\n", date.year, date.month, date.day);
else
printf("null\n");
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}示例 2:SQLGetData
C
void query(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
int id;
char name[20];
SQL_DATE_STRUCT date;
SQLLEN len[3] = { 0 };
ret = SQLExecDirect(hstmt, "SELECT id, name, created FROM tab_test", SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
while (SQLFetch(hstmt) == SQL_SUCCESS)
{
SQLGetData(hstmt, 1, SQL_C_LONG, &id, 0, &len[0]);
SQLGetData(hstmt, 2, SQL_C_CHAR, name, 20, &len[1]);
SQLGetData(hstmt, 3, SQL_C_DATE, &date, 0, &len[2]);
printf(len[0] != -1 ? "%d, " : "%s, ", len[0] != -1 ? id : "null");
printf("%s, ", len[1] != -1 ? name : "null");
if (len[2] != -1)
printf("%04d-%02d-%02d\n", date.year, date.month, date.day);
else
printf("null\n");
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}4.4 存储过程调用
SQL
-- 创建存储过程
CREATE OR REPLACE PROCEDURE proc_add(a INT, b INT, c OUT INT)
AS
BEGIN
c := a + b;
END;C
void procedure(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
const char* sql = "proc_add(?, ?, ?)";
int a = 1;
int b = 2;
int sum;
SQLLEN len[3] = { 0 };
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &a, 4, &len[0]);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &b, 4, &len[1]);
SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &sum, 4, &len[2]);
ret = SQLExecDirect(hstmt, sql, SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
else
printf("%d + %d = %d\n", a, b, sum);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}4.5 存储函数调用
SQL
-- 创建存储函数
CREATE OR REPLACE FUNCTION func_add(a INT, b INT)
RETURN INT
AS
BEGIN
RETURN a + b;
END;C
void function(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
const char* sql = "func_add(?, ?)";
int a = 1;
int b = 2;
int sum;
SQLLEN len[3] = { 0 };
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &a, 4, &len[0]);
SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &b, 4, &len[1]);
SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &sum, 4, &len[2]);
ret = SQLExecDirect(hstmt, sql, SQL_NTS);
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
else
printf("%d + %d = %d\n", a, b, sum);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}4.6 LOB 插入
C
void insertLob(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
const char* sql = "INSERT INTO tab_lob (lob) VALUES(?)";
SQLPrepare(hstmt, sql, SQL_NTS);
SQLLEN len = SQL_LEN_DATA_AT_EXEC(0);
SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 0, 0, (SQLPOINTER)1, 0, &len);
SQLPOINTER token = NULL;
FILE* fp = fopen("blob.png", "rb");
size_t size;
char buf[4096];
ret = SQLExecute(hstmt);
while (ret == SQL_NEED_DATA)
{
ret = SQLParamData(hstmt, &token);
if (ret == SQL_NEED_DATA)
{
do {
size = fread(buf, 1, 4096, fp);
if (size <= 0) break;
SQLPutData(hstmt, buf, size);
} while (1);
}
}
if (ret != SQL_SUCCESS)
printError(hstmt, SQL_HANDLE_STMT);
fclose(fp);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}4.7 LOB 查询
C
void queryLob(SQLHDBC hdbc)
{
SQLHSTMT hstmt;
SQLRETURN ret;
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
const char* sql = "SELECT lob FROM tab_test WHERE id = 1";
SQLExecDirect(hstmt, sql, SQL_NTS);
SQLFetch(hstmt);
char buf[1024];
SQLLEN len;
FILE* fp = fopen("blob_out.png", "wb");
while (TRUE)
{
ret = SQLGetData(hstmt, 1, SQL_CHAR, buf, 1024, &len);
if (ret != SQL_SUCCESS)
break;
fwrite(buf, 1, len, fp);
}
fclose(fp);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}