虚谷 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(HDBC hdbc);
void query(HDBC hdbc);
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, 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);
return;
}
insert(hdbc);
query(hdbc);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
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);
const char* 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;
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);
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);
}