注册
达梦odbc测试
培训园地/ 文章详情 /

达梦odbc测试

yyds 2026/03/18 267 0 0

1前言
ODBC 提供访问不同类型的数据库的途径。结构化查询语言 SQL 是一种用来访问数据库的语言。通过使用 ODBC,应用程序能够使用相同的源代码和各种各样的数据库交互。这使得开发者不需要以特殊的数据库管理系统 DBMS 为目标,或者了解不同支撑背景的数据库的详细细节,就能够开发和发布客户/服务器应用程序。
DM ODBC 3.0 遵照 Microsoft ODBC 3.0 规范设计与开发,实现了 ODBC 应用程序与 DM 数据库的互连接口。用户可以直接调 DM ODBC 3.0 接口函数访问 DM,也可以使用可视化编程工具如 C++ Builder、PowerBuilder 等利用 DM ODBC 3.0 访问 DM 数据库。
2开发环境准备
2.1达梦数据库版本
名称 版本
DM 数据库 DM 8.0 及以上版本

2.2数据源创建
请参考数据库环境准备。
2.3数据源创建
2.3.1Windows环境创建 ODBC 数据源
在客户使用 ODBC 方法访问 DM 数据库服务器之前,必须先对自己的应用程序所用的 ODBC 数据源进行配置。本小节将介绍如何安装和配置 ODBC 数据源。
在 Windows 上使用 ODBC 数据源管理程序,配置 ODBC 数据源的步骤如下:
1.在控制面板上访问 ODBC 构件,显示 ODBC 数据源管理器对话框,如下图所示:
图片1.png

ODBC 数据源管理器对话框包含的标签如下所示:
用户 DSN:添加、删除或配置本机上的数据源,它们只可由当前用户使用。 系统 DSN:添加、删除或配置本机上的数据源,它们可由任何用户使用。 文件 DSN:添加、删除或配置在分离文件中的数据源。这些文件可以被安装了同样数据库驱动器的用户共享。 驱动程序:列出了安装在客户机上的数据库驱动器。 跟踪:用于测试你的数据库应用程序。它跟踪客户机和数据库服务器之间的 ODBC API 的调用。 连接池:允许不同的应用程序自动复用多个连接。这有助于限制和数据库服务器的通信过载。 关于:显示主要 ODBC 组件的版本。
1.设置和配置一个系统 DSN,请单击系统 DSN 标签,单击添加按钮增加一个新的 DSN,如下图所示:
图片2.png
2.选择 DM ODBC 3.0 驱动程序即DM ODBC DRIVER,单击【完成】按钮,显示 DM ODBC 3.0 数据源配置对话框,如下图所示:
图片5.png
3.输入数据源的名称、描述,并选择你想要连接的数据库服务器的名字使用的端口号、验证登录用户 ID 真伪的方式。如果使用 DMServer 验证方式则需要输入登录数据源的 ID 以及密码等信息,选择系统提示信息的语种,以及选择是否使用 DMServer 的增强选项。
4.单击测试按钮测试配置的数据源是否正确,如下图所示:
图片6.png
5.单击确定按钮保存新的系统数据源,如下图所示:
图片7.png
6.单击确定按钮关闭 ODBC 数据源管理器对话框。
2.3.2Linux 环境创建 ODBC 数据源
1.下载需要的 unixODBC 和 unixODBC-devel 包。
2.安装所需的 安装 unixODBC 和 unixODBC-devel。
[root@localhost unixodbc]# rpm -ivh unixODBC-devel-2.3.1-14.el7.x86_64.rpm unixODBC-2.3.1-14.el7.src.rpm
(1)可能出现的问题一,此处为版本不一致,安装 unixODBC 和 unixODBC-devel的版本需要一致。
unixODBC(x86-32) = 2.3.1-14.el7 is needed by unixODBC-devel-2.3.1-14.el7.i686
Updating / installing...
1:unixODBC-2.3.9-4.el9 ################################# [100%]
(2)可能出现的问题二,此处需要安装相关依赖。
error: Failed dependencies:
libesoobS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libmimerS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libnn.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbccr.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbcdrvcfg1S.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbcdrvcfg2S.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbcminiS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbcnnS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libodbctxtS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
liboplodbcS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
liboraodbcS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libsapdbS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libtdsS.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
libtemplate.so.2 is needed by unixODBC-devel-2.3.1-14.el7.i686
解决方法如下(使用YUM自动处理依赖关系):
[root@localhost unixodbc]#
sudo yum localinstall unixODBC-devel-2.3.1-14.el7.x86_64.rpm
(3)可能出现的问题三,此处需要创建一个名为mockbuild的用户,并将该用户的默认shell设置为/sbin/nologin。
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
warning: user mockbuild does not exist - using root
warning: group mockbuild does not exist - using root
解决方法如下:
useradd -s /sbin/nologin mockbuild
3.查看安装结果。
[root@localhost unixodbc]#odbcinst -j
unixODBC 2.3.1
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 4
SQLLEN Size........: 4
SQLSETPOSIROW Size.: 2

4.编辑 /etc/odbcinst.ini ,如下所示:
[DM8 ODBC DRIVER]
Description = ODBC DRIVER FOR DM8
Driver =/home/dmdba/dmdbms/bin/libdodbc.so

注意: odbcinst.ini 中的Drive应指向 DM安装目录下的 /bin/libdodbc.so 下,本次示例中 DM 路径为 /home/dmdba/dmdbms 。
5.编辑 /etc/odbc.ini ,如下所示:
[DM8]
Description = DM ODBC DSN
Driver = DM8 ODBC DRIVER
SERVER = localhost
UID = SYSDBA
PWD = SYSDBa111
TCP_PORT = 5236

注意:odbc.ini 中的 Driver 内容一定要与 odbcinst.ini 中的 DM 驱动定义的节点名称相同。odbc.ini 中的 SERVER 可以输入数据库服务器的 IP 。
6.测试连接,出现以下内容说明连接成功。
isql dm8
图片8.png

注意:安装 odbc 版本时需要unixODBC-devel与达梦数据库版本一致,尽量使用 x86_64 版本的unixODBC-devel,不要使用 i686 版本的,不然有可能出现下面这个错误,出现下面这个错误还有可能是环境变量对的原因把以下环境变量写入 /etc/profile 或 source ~/.bashrc 。
[dmdba@localhost dm_install]$ isql -v dm8
[01000][unixODBC][Driver Manager]Can't open lib '/home/dmdba/dmdbms/bin/libdodbc.so' : file not found
[ISQL]ERROR: Could not SQLConnect

export PATH
export DM_HOME=/home/dmdba/dmdbms
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$DM_HOME/bin"
export PATH=$PATH:/$HOME/bin:$/HOME/.local/bin:$DM_HOME/bin

2.4环境准备
2.4.1Window环境
本次测试使用的是viusal studio 工具。
2.4.1.1确认编译版本
(1)先确认达梦安装包版本,例如以下就是64位版本,64位版本只能创建 64 位 odbc 数据源。

(2)确认 MSVC 和 Windows Kits 版本为64 位,加到Path环境变量。

2.4.1.2添加相关lib包和环境变量
右键项目,点击属性,在 VC++ 目录添加相关依赖。

包含目录里面添加Windows Kits 相关版本,以及相关头文件。
C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\um;C:\Program Files (x86)\WindowsKits\10\Include\10.0.22621.0\shared;C:\dmdbms\include;$(IncludePath)

库目录添加相关lib目录。
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\um\x64;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64;C:\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.43.34808\lib\x64;C:\dmdbms\drivers\odbc

添加链接器附加库目录,此处添加需要链接的库文件名,。
C:\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.43.34808\lib\x64;C:\dmdbms\include;C:\dmdbms\drivers\odbc;C:\dmdbms\bin;%(AdditionalLibraryDirectories)

右键资源文件,添加达梦相关 dodbc.lib ,此文件位于达梦 driver 下的 odbc下。

添加输入,在附加依赖项添加 dodbc.lib及相关lib。
dodbc.lib;kernel32.lib;user32.lib;%(AdditionalDependencies)

2.4.1.3可能出现的问题
1.LINK : fatal error LNK1104: 无法打开文件“kernel32.lib”。
原因为编译版本和dodbc.lib版本不一致,解决方法为修改编译版本为dodbc.lib 版本。

2.LINK : fatal error LNK1104: 无法打开文件“ucrtd.lib”。
解决方法在项目属性页 -> VC++目录 -> 库目录下添加\ucrt\x64,例如本次测试目录为
C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\ucrt\x64;
3.LNK1104 无法打开文件“libcmtd.lib”。
解决方法为属性页->链接器->常规->附加库目录里面添加 MSVC 的 lib 下x64 版本目录,例如本次测试路径为
C:\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.43.34808\lib\x64;
2.4.1.4创建并测试代码
1.测试连接代码如下
#include<Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hsmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
/* 申请一个环境句柄 /
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
/
设置环境句柄的 ODBC 版本 /
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
SQL_IS_INTEGER);
/
申请一个连接句柄 */
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

// 定义非 const 的 SQLWCHAR 数组存储字符串
SQLWCHAR dsn[] = L"DM";
SQLWCHAR user[] = L"SYSDBA";
SQLWCHAR pwd[] = L"SYSDBA";

// 连接数据源
sret = SQLConnect(hdbc, dsn, SQL_NTS, user, SQL_NTS, pwd, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
/* 连接数据源失败! */
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 断开与数据源之间的连接 /
SQLDisconnect(hdbc);
/
释放连接句柄 /
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
/
释放环境句柄 */
SQLFreeHandle(SQL_HANDLE_ENV, henv);

return 0;
}

2.测试增删改查
#include<Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hstmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
int out_c1 = 0;
SQLCHAR out_c2[20] = { 0 };
SQLLEN out_c1_ind = 0;
SQLLEN out_c2_ind = 0;
SQLWCHAR dsn[] = L"DM8";
SQLWCHAR user[] = L"SYSDBA";
SQLWCHAR pwd[] = L"SYSDBA";
SQLWCHAR del[] = L"delete from PRODUCTION.PRODUCT_CATEGORY";
SQLWCHAR in[] = L"insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values('语文'), ('数学'), ('英语'), ('体育') ";
SQLWCHAR del2[] = L"delete from PRODUCTION.PRODUCT_CATEGORY where name='数学'";
SQLWCHAR up[] = L"update PRODUCTION.PRODUCT_CATEGORY set name = '英语-新课标' where name='英语'";
SQLWCHAR se[] = L"select * from PRODUCTION.PRODUCT_CATEGORY";

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, dsn, SQL_NTS, user, SQL_NTS, pwd, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

//清空表,初始化测试环境
sret = SQLExecDirect(hstmt, del, SQL_NTS);

//插入数据
sret = SQLExecDirect(hstmt, in, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: insert fail\n");
}
printf("odbc: insert success\n");

//删除数据
sret = SQLExecDirect(hstmt, del2, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: delete fail\n");
}
printf("odbc: delete success\n");

//更新数据
sret = SQLExecDirect(hstmt, up, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: update fail\n");
}
printf("odbc: update success\n");

//查询数据
SQLExecDirect(hstmt, se, SQL_NTS);
SQLBindCol(hstmt, 1, SQL_C_SLONG, &out_c1, sizeof(out_c1), &out_c1_ind);
SQLBindCol(hstmt, 2, SQL_C_CHAR, &out_c2, sizeof(out_c2), &out_c2_ind);

printf("odbc: select from table...\n");
while (SQLFetch(hstmt) != SQL_NO_DATA)
{
printf("c1 = %d, c2 = %s ,\n", out_c1, out_c2);
}
printf("odbc: select success\n");

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}

3.测试占位符。
#include<Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hstmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
SQLWCHAR dsn[] = L"DM8";
SQLWCHAR user[] = L"SYSDBA";
SQLWCHAR pwd[] = L"SYSDBA";
SQLWCHAR sql[] = L"insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values(?)";
SQLCHAR in_c1[20] = { 0 };
SQLLEN in_c1_ind_ptr;

memcpy(in_c1, "物理", 8);
in_c1_ind_ptr = 8;

int out_c1 = 0;
SQLCHAR out_c2[20] = { 0 };
SQLLEN out_c1_ind = 0;
SQLLEN out_c2_ind = 0;

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, dsn, SQL_NTS, user, SQL_NTS, pwd, SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

//清空表,初始化测试环境
sret = SQLExecDirect(hstmt, (SQLWCHAR*)L"delete from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);

//绑定参数方式插入数据
printf("insert with bind..\nsql: %s\npara: %s\n", (char*)sql, (char*)in_c1);
sret = SQLPrepare(hstmt, sql, SQL_NTS);
sret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(in_c1), 0, in_c1, 0, &in_c1_ind_ptr);
sret = SQLExecute(hstmt);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: insert into table with bind fail!\n");
}
printf("odbc: insert into table with bind success!\n");

//查询数据
SQLExecDirect(hstmt, (SQLWCHAR*)L"select * from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);
SQLBindCol(hstmt, 1, SQL_C_SLONG, &out_c1, sizeof(out_c1), &out_c1_ind);
SQLBindCol(hstmt, 2, SQL_C_CHAR, &out_c2, sizeof(out_c2), &out_c2_ind);

printf("odbc: select from table...\n");
while (SQLFetch(hstmt) != SQL_NO_DATA)
{
printf("c1 = %d, c2 = %s ,\n", out_c1, out_c2);
}
printf("odbc: select success\n");

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}

4.测试大字段。
#include<Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

#define IN_FILE "C:\Users\Administrator\Desktop\test1.txt"
#define OUT_FILE "C:\Users\Administrator\Desktop\test2.txt"
#define CHARS 80*1024

HENV henv;
HDBC hdbc;
HSTMT hstmt;
SQLRETURN sret;

SQLSMALLINT errmsglen;
SQLINTEGER errnative;
SQLWCHAR errmsg[255];
SQLWCHAR errstate[5];

int main(void)
{
FILE* pfile = NULL;
SQLCHAR tmpbuf[CHARS];
SQLLEN len = 0;
SQLLEN val_len = 0;

SQLLEN c1 = 1;
SQLLEN c2 = SQL_DATA_AT_EXEC;
SQLLEN c1_ind_ptr = 0;
SQLLEN c2_ind_ptr = SQL_DATA_AT_EXEC;
PTR c2_val_ptr;

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, (SQLWCHAR*)L"dm8", SQL_NTS, (SQLWCHAR*)L"SYSDBA", SQL_NTS, (SQLWCHAR*)L"SYSDBA", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

// 清空表,初始化测试环境
sret = SQLExecDirect(hstmt, (SQLWCHAR*)L"drop table PRODUCTION.BIG_DATA", SQL_NTS);
sret = SQLExecDirect(hstmt, (SQLWCHAR*)L"create table PRODUCTION.BIG_DATA(c1 int, c2 blob)", SQL_NTS);

// ---------- 读取文件,插入到 LOB 列 ----------
errno_t open_err = fopen_s(&pfile, IN_FILE, "rb");
if (open_err != 0)
{
printf("open %s fail (error code: %d)\n", IN_FILE, open_err);
return SQL_ERROR;
}

sret = SQLPrepare(hstmt, (SQLWCHAR*)L"insert into PRODUCTION.BIG_DATA(c1,c2) values(?,?)", SQL_NTS);
sret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(c1), 0, &c1, sizeof(c1), NULL);
sret = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sizeof(c2), 0, (void*)1, sizeof(c2), &c2_ind_ptr);
sret = SQLExecute(hstmt);

if (sret == SQL_NEED_DATA)
{
if (SQLParamData(hstmt, &c2_val_ptr) == SQL_NEED_DATA)
{
while (!feof(pfile))
{
len = fread(tmpbuf, sizeof(char), CHARS, pfile);
if (len <= 0)
{
printf("fread %s fail\n", IN_FILE);
fclose(pfile);
return SQL_ERROR;
}
SQLPutData(hstmt, tmpbuf, len);
}
}
SQLParamData(hstmt, &c2_val_ptr);
}
else if (sret == SQL_ERROR)
{
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, errstate, &errnative, errmsg, sizeof(errmsg), &errmsglen);
printf("error:%s\n", errmsg);
fclose(pfile);
return SQL_ERROR;
}

printf("odbc: insert data into col of lob success\n");
fclose(pfile);
pfile = NULL;

// ---------- 读取 LOB 列数据,写入文件 ----------
errno_t open_err_out = fopen_s(&pfile, OUT_FILE, "wb");
if (open_err_out != 0)
{
printf("open %s fail (error code: %d)\n", OUT_FILE, open_err_out);
return SQL_ERROR;
}

sret = SQLExecDirect(hstmt, (SQLWCHAR*)L"select c1, c2 from PRODUCTION.BIG_DATA", SQL_NTS);
sret = SQLBindCol(hstmt, 1, SQL_C_SLONG, &c1, sizeof(c1), &c1_ind_ptr);

while (SQLFetch(hstmt) != SQL_NO_DATA)
{
while (1)
{
sret = SQLGetData(hstmt, 2, SQL_C_BINARY, tmpbuf, CHARS, &val_len);
if ((sret) == SQL_SUCCESS || (sret) == SQL_SUCCESS_WITH_INFO)
{
len = val_len > CHARS ? CHARS : val_len;
fwrite(tmpbuf, sizeof(char), len, pfile);
continue;
}
break;
}
}

printf("odbc: get data from col of lob success\n");
fclose(pfile);
pfile = NULL;

// 释放资源
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}

2.4.2Linux环境
2.4.2.1查看gcc版本
通过 gcc --version 命令查看当前 gcc 版本。
[dmdba@localhost dm_install]$ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2.4.2.2创建测试目录及相关代码
1.设置目录结构,编写 makefile 文件及其他相关文件。

1.1 makefile 文件内容如下:
CC=gcc

includepath=$(DM_HOME)/include
libpath=$(DM_HOME)/bin
vpath=./

CFLAGS=-I$(includepath) -DDM64 -Wall
LINKFLAGS=-L$(libpath) -ldodbc -Wall -Wl,-rpath $(libpath)

%.o:%.c
$(CC) -g -c $(CFLAGS) $< -o $@

object_file1=odbc_conn.o
object_file2=odbc_dml.o
object_file3=odbc_bind.o
object_file4=odbc_lob.o

object_files=odbc_conn.o odbc_dml.o odbc_bind.o odbc_lob.o

final_objects=odbc_conn odbc_dml odbc_bind odbc_lob

all : $(final_objects)

.PHONY : all clean rebuild

odbc_conn : $(object_file1)
$(CC) -o $@ $(object_file1) -g $(LINKFLAGS)
@echo make ok.

odbc_dml : $(object_file2)
$(CC) -o $@ $(object_file2) -g $(LINKFLAGS)
@echo make ok.

odbc_bind : $(object_file3)
$(CC) -o $@ $(object_file3) -g $(LINKFLAGS)
@echo make ok.

odbc_lob : $(object_file4)
$(CC) -o $@ $(object_file4) -g $(LINKFLAGS)
@echo make ok.

clean :
@rm -rf $(object_files)
@rm -rf $(final_objects)

rebuild : clean all

1.2 ODBC 接口登录登出示例程序 odbc_conn.c 如下:
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hsmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
/* 申请一个环境句柄 /
SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
/
设置环境句柄的 ODBC 版本 /
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
SQL_IS_INTEGER);
/
申请一个连接句柄 */
SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

sret = SQLConnect(hdbc, (SQLCHAR *)"dm8", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS, (SQLCHAR )"SYSDBA", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
/
连接数据源失败! */
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 断开与数据源之间的连接 /
SQLDisconnect(hdbc);
/
释放连接句柄 /
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
/
释放环境句柄 */
SQLFreeHandle(SQL_HANDLE_ENV, henv);

return 0;
}
1.3 ODBC 接口增、删、改、查四个基本操作,示例程序 odbc_dml.c 如下:
#include <stdio.h>
#include <stdlib.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hstmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
int out_c1 = 0;
SQLCHAR out_c2[20]= { 0 };
SQLLEN out_c1_ind = 0;
SQLLEN out_c2_ind = 0;

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, (SQLCHAR *)"dm8", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

//清空表,初始化测试环境
sret = SQLExecDirect(hstmt, (SQLCHAR *) "delete from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);

//插入数据
sret = SQLExecDirect(hstmt, (SQLCHAR *) "insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values('语文'), ('数学'), ('英语'), ('体育') ", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: insert fail\n");
}
printf("odbc: insert success\n");

//删除数据
sret = SQLExecDirect(hstmt, (SQLCHAR *) "delete from PRODUCTION.PRODUCT_CATEGORY where name='数学' ", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: delete fail\n");
}
printf("odbc: delete success\n");

//更新数据
sret = SQLExecDirect(hstmt, (SQLCHAR *) "update PRODUCTION.PRODUCT_CATEGORY set name = '英语-新课标' where name='英语' ", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: update fail\n");
}
printf("odbc: update success\n");

//查询数据
SQLExecDirect(hstmt, (SQLCHAR *) "select * from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);
SQLBindCol(hstmt, 1, SQL_C_SLONG, &out_c1, sizeof(out_c1), &out_c1_ind);
SQLBindCol(hstmt, 2, SQL_C_CHAR, &out_c2, sizeof(out_c2), &out_c2_ind);

printf("odbc: select from table...\n");
while(SQLFetch(hstmt) != SQL_NO_DATA)
{
printf("c1 = %d, c2 = %s ,\n", out_c1, out_c2);
}
printf("odbc: select success\n");

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
1.4 ODBC 接口绑定变量示例程序 odbc_bind.c 如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hstmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

int main(void)
{
SQLCHAR sql[]="insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values(?)";
SQLCHAR in_c1[20] = { 0 };
SQLLEN in_c1_ind_ptr;

memcpy(in_c1, "物理", 8);
in_c1_ind_ptr = 8;

int out_c1 = 0;
SQLCHAR out_c2[20]= { 0 };
SQLLEN out_c1_ind = 0;
SQLLEN out_c2_ind = 0;

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, (SQLCHAR *)"dm8", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

//清空表,初始化测试环境
sret = SQLExecDirect(hstmt, (SQLCHAR *) "delete from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);

//绑定参数方式插入数据
printf( "insert with bind..\nsql: %s\npara: %s\n", (char*)sql, (char*)in_c1);
sret = SQLPrepare(hstmt, sql, SQL_NTS);
sret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(in_c1), 0, in_c1, 0, &in_c1_ind_ptr);
sret = SQLExecute(hstmt);
if (RC_NOTSUCCESSFUL(sret)) {
printf( "odbc: insert into table with bind fail!\n" );
}
printf( "odbc: insert into table with bind success!\n" );

//查询数据
SQLExecDirect(hstmt, (SQLCHAR *) "select * from PRODUCTION.PRODUCT_CATEGORY", SQL_NTS);
SQLBindCol(hstmt, 1, SQL_C_SLONG, &out_c1, sizeof(out_c1), &out_c1_ind);
SQLBindCol(hstmt, 2, SQL_C_CHAR, &out_c2, sizeof(out_c2), &out_c2_ind);

printf("odbc: select from table...\n");
while(SQLFetch(hstmt) != SQL_NO_DATA)
{
printf("c1 = %d, c2 = %s ,\n", out_c1, out_c2);
}
printf("odbc: select success\n");

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
1.5 ODBC 接口大字段操作包括大字段的插入,查询等。示例程序 odbc_lob.c 如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sql.h>
#include <sqltypes.h>
#include <sqlext.h>

/* 检测返回代码是否为成功标志,当为成功标志返回 TRUE,否则返回 FALSE /
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)
/
检测返回代码是否为失败标志,当为失败标志返回 TRUE,否则返回 FALSE */
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

#define IN_FILE "/data/c_test_code/DM8_SQL.pdf"
#define OUT_FILE "/data/c_test_code/DM8_SQL2.pdf"
#define CHARS 80*1024 //一次读取和写入的字节数 80 KB

HENV henv;/* 环境句柄 /
HDBC hdbc;/
连接句柄 /
HSTMT hstmt;/
语句句柄 /
SQLRETURN sret; /
返回代码 */

SQLSMALLINT errmsglen;
SQLINTEGER errnative;
UCHAR errmsg[255];
UCHAR errstate[5];

int main(void)
{
FILE* pfile = NULL;
SQLCHAR tmpbuf[CHARS];
SQLLEN len = 0;
SQLLEN val_len = 0;

SQLLEN c1 =1;
SQLLEN c2 = SQL_DATA_AT_EXEC;
SQLLEN c1_ind_ptr = 0;
SQLLEN c2_ind_ptr = SQL_DATA_AT_EXEC;
PTR c2_val_ptr;

/* 申请句柄 */
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);

sret = SQLConnect(hdbc, (SQLCHAR *)"dm8", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS, (SQLCHAR *)"SYSDBA", SQL_NTS);
if (RC_NOTSUCCESSFUL(sret)) {
printf("odbc: fail to connect to server!\n");
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
exit(0);
}
printf("odbc: connect to server success!\n");

/* 申请一个语句句柄 */
SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

//清空表,初始化测试环境
sret = SQLExecDirect(hstmt, (SQLCHAR *)"drop table PRODUCTION.BIG_DATA", SQL_NTS);
sret = SQLExecDirect(hstmt, (SQLCHAR *)"create table PRODUCTION.BIG_DATA(c1 int, c2 blob)", SQL_NTS);

//读取文件,插入到 LOB 列
pfile = fopen(IN_FILE, "rb");
if (pfile == NULL)
{
printf("open %s fail\n", IN_FILE);
return SQL_ERROR;
}

sret = SQLPrepare(hstmt, (SQLCHAR *)"insert into PRODUCTION.BIG_DATA(c1,c2) values(?,?)", SQL_NTS);
sret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(c1), 0, &c1, sizeof(c1), NULL);
sret = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sizeof(c2), 0, (void )1, sizeof(c2), &c2_ind_ptr);
sret = SQLExecute(hstmt);
if (sret == SQL_NEED_DATA)
{
if (SQLParamData(hstmt, &c2_val_ptr) == SQL_NEED_DATA) /
绑定数据 /
{
while (!feof(pfile))
{
len = fread(tmpbuf, sizeof(char), CHARS, pfile);
if (len <= 0)
{
return SQL_ERROR;
}
SQLPutData(hstmt, tmpbuf, len);
}
}
SQLParamData(hstmt, &c2_val_ptr); /
绑定数据 */
}else if( sret == SQL_ERROR )
{
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, errstate, &errnative, errmsg, sizeof(errmsg), &errmsglen);
printf( "error:%s\n", errmsg );
}

printf("odbc: insesret data into col of lob success\n");
fclose(pfile);

//读取 LOB 列数据,写入文件
pfile = fopen((const char *)OUT_FILE, "wb");
if (pfile == NULL)
{
printf("open %s fail\n", OUT_FILE);
return SQL_ERROR;
}

sret = SQLExecDirect(hstmt, (SQLCHAR *)"select c1, c2 from PRODUCTION.BIG_DATA", SQL_NTS);
sret = SQLBindCol(hstmt, 1, SQL_C_SLONG, &c1, sizeof(c1), &c1_ind_ptr);
while(SQLFetch(hstmt) != SQL_NO_DATA)
{
while(1)
{
sret = SQLGetData(hstmt, 2, SQL_C_BINARY, tmpbuf, CHARS, &val_len);
if ((sret) == SQL_SUCCESS || (sret) == SQL_SUCCESS_WITH_INFO)
{
len = val_len > CHARS ? CHARS : val_len;
fwrite(tmpbuf, sizeof(char), len, pfile);
continue;
}
break;
}
}

fclose(pfile);
printf("odbc: get data from col of lob success\n");

SQLFreeHandle(SQL_HANDLE_STMT, hstmt);

SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
2.4.2.3使用 make 命令生成相关文件
[dmdba@localhost odbctest]$ make

2.4.2.4测试代码
[dmdba@localhost odbctest]$ ./odbc_conn
odbc: connect to server success!
[dmdba@localhost odbctest]$ ./odbc_dml
odbc: connect to server success!
odbc: insert success
odbc: delete success
odbc: update success
odbc: select from table...
c1 = 8, c2 = 语文 ,
c1 = 10, c2 = 英语-新课标 ,
c1 = 11, c2 = 体育 ,
odbc: select success
[dmdba@localhost odbctest]$ ./odbc_bind
odbc: connect to server success!
insert with bind..
sql: insert into PRODUCTION.PRODUCT_CATEGORY(NAME) values(?)
para: 物理
odbc: insert into table with bind success!
odbc: select from table...
c1 = 12, c2 = 物理 ,
odbc: select success
[dmdba@localhost odbctest]$ ./odbc_lob
odbc: connect to server success!
odbc: insesret data into col of lob success
odbc: get data from col of lob success

3需要理解的概念
c/c++, 附加库目录,代表的是c/c文件编译时所需要的头文件,而资源编译时也是需要附加包含库目录的,而vc的包含目录,代表的是全局项目的包含目录
配置过VC里面的库,C/C里面的就可以不用配置
VS项目中的包含目录、库目录、附加包含目录、附加库目录、附加依赖项均在”项目->属性->配置属性”下进行配置,具体说明如下:
VC++目录:
包含目录:寻找#include<xxxx.h>中的xxxx.h的搜索目录

库目录:寻找.lib文件的搜索目录
C/C++:
常规->附加包含目录:寻找#include<xxxx.h>中的xxxx.h的搜索目录(每一项对应一个文件夹XXXX,文件夹中包含了编译时所需的头文件,使用时直接#include即可)

链接器:
常规->附加库目录:寻找.lib文件的搜索目录
输入->附加依赖项:lib库(C++的库会把函数、类的声明放在*.h中,实现放在*.cpp或*.cc中。编译之后,.cpp,.cc,*.c会被打包成一个.lib文件,这样可以保护源代码)

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服