C语言DCI(OCI)方式连接DM数据库

一、背景

近期用户使用DCI的方式连接达梦数据库出现中文乱码的问题,所以决定写一个测试Demo。

因为使用DCI的方式连接,适配中心https://eco.dameng.com/docs/zh-cn/app-dev/index.html 也没有相关的例子。为避免版权纠纷所以在DM8以后的数据库中就没有DCI相关的资料文档了。实际上是将DCI的文档跟数据库这块单独分开了。所以如果要用就需要单独去找或者申请。DCI的相关文档在资料包中有。

需要说明的是,本人非开发人员,所以在C++代码编写思路或者使用方式上难免有些低级操作,调试中也是参考了网上很多朋友发的帖子,如有错误或者修改建议,欢迎指正。谢谢!

环境

操作系统:Window 10

数据库版本:Dm8.1.2.18

开发工具:Visual Studio 2017

DCI的库:在资料中,整篇文章用的是解压后的dmoci目录的文件

注意:DM8相对较老的一些版本在安装数据库以后就可以在“安装目录/drivers”下看到dci、oci目录,但是新版本已经将oci单独打包,名字为xxxx_dmdci.zip(资料网盘已提供,本章用的是压缩包中dmoci目录的库),内有oci和occi所需的头文件和库文件。数据库的drivers目录仍然保留有dci目录与库文件。需要oci相关文件的朋友需要注意一下这里。准确来说本次的文章应该是OCI的方式来连接,所以文章中的所有dci可以统称为oci。

二、数据库的测试SQL

把sql装载到库里

DROP TABLE "SYSDBA"."PERSON" CASCADE;CREATE TABLE "SYSDBA"."PERSON"
("PERSONID" INT IDENTITY(1,1) NOT NULL,"SEX" CHAR(1) NOT NULL,"NAME" VARCHAR(50) NOT NULL,"EMAIL" VARCHAR(50) NULL,"PHONE" VARCHAR(25) NULL,CLUSTER PRIMARY KEY("PERSONID") ENABLE
);SET IDENTITY_INSERT "SYSDBA"."PERSON" ON;
INSERT INTO "SYSDBA"."PERSON"("PERSONID","SEX","NAME","EMAIL","PHONE") VALUES(1,'F','李丽','lily@sina.com','02788548562');
INSERT INTO "SYSDBA"."PERSON"("PERSONID","SEX","NAME","EMAIL","PHONE") VALUES(2,'M','王刚','','02787584562');
INSERT INTO "SYSDBA"."PERSON"("PERSONID","SEX","NAME","EMAIL","PHONE") VALUES(3,'M','李勇','','02782585462');
INSERT INTO "SYSDBA"."PERSON"("PERSONID","SEX","NAME","EMAIL","PHONE") VALUES(4,'F','郭艳','','02787785462');
INSERT INTO "SYSDBA"."PERSON"("PERSONID","SEX","NAME","EMAIL","PHONE") VALUES(5,'F','孙丽','','13055173012');
SET IDENTITY_INSERT "SYSDBA"."PERSON" OFF;COMMIT;

三、新建项目

  1. 新建项目

  1. 新建源文件并新建一个demo.cpp的文件


/************************************************************************/
/* DCI编程实例 (较DCI手册示例有改动)                                  */
/************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "DCI.h"// 声明句柄
DCIEnv* envhp;              /* 环境句柄 */
DCISvcCtx* svchp;           /* 服务环境句柄 */
DCIServer* srvhp;           /* 服务器句柄 */
DCISession* authp;          /* 会话句柄 */
DCIStmt* stmthp;            /* 语句句柄 */
DCIDescribe* dschp;         /* 描述句柄 */
DCIError* errhp;            /* 错误句柄 */
DCIDefine* defhp[3];        /* 定义句柄 */
DCIBind* bidhp[4];          /* 绑定句柄 */
sb2 ind[3];                 /* 指示符变量 */// 绑定select结果集的参数
text szpersonid[11];        /* 存储personid列 */
text szsex[2];              /* 存储sex列 */
text szname[51];            /* 存储name列 */
text szemail[51];           /* 存储mail列 */
text szphone[26];           /* 存储phone列 */
char sql[256];              /* 存储执行的sql语句 */int main(int argc, char* argv[])
{char strServerName[50];char strUserName[50];char strPassword[50];int ret;text errbuf[100];// 设置服务器,用户名和密码strcpy(strServerName, "localhost");strcpy(strUserName, "SYSDBA");strcpy(strPassword, "SYSDBA");// 初始化OCI应用环境OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL);// 初始化环境句柄OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0);// 分配句柄OCIHandleAlloc(envhp, (dvoid**)&svchp, OCI_HTYPE_SVCCTX, 0, 0);            /* 服务器环境句柄 */OCIHandleAlloc(envhp, (dvoid**)&srvhp, OCI_HTYPE_SERVER, 0, 0);            /* 服务器句柄 */OCIHandleAlloc(envhp, (dvoid**)&authp, OCI_HTYPE_SESSION, 0, 0);     /* 会话句柄 */OCIHandleAlloc(envhp, (dvoid**)&errhp, OCI_HTYPE_ERROR, 0, 0);            /* 错误句柄 */OCIHandleAlloc(envhp, (dvoid**)&dschp, OCI_HTYPE_DESCRIBE, 0, 0);     /* 描述符句柄 */// 连接服务器OCIServerAttach(srvhp, errhp, (text*)strServerName,(sb4)strlen(strServerName), OCI_DEFAULT);// 设置用户名和密码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);// 设置服务器环境句柄属性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);// 创建并开始一个用户会话OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT);OCIHandleAlloc(envhp, (dvoid**)&stmthp, OCI_HTYPE_STMT, 0, 0);         /* 语句句柄 *//************************************************************************//* 查询person表                                                            *//************************************************************************/strcpy(sql, "select personid, name, phone from sysdba.person");// 准备SQL语句OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);// 绑定输出列OCIDefineByPos(stmthp, &defhp[0], errhp, 1, (ub1*)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*)szphone,sizeof(szphone), SQLT_STR, &ind[2], 0, 0, OCI_DEFAULT);// 执行SQL语句ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4)0, 0, NULL, NULL, OCI_DEFAULT);if (ret != 0){OCIErrorGet(errhp, 1, NULL, &ret, (OraText*)errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);printf("\n%s\n", errbuf);}printf("%-10s%-10s%-10s\n", "PERSONID", "NAME", "PHONE");while ((OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)) != OCI_NO_DATA){printf("%-10s", szpersonid);printf("%-10s", szname);printf("%-10s\n", szphone);}/************************************************************************//* 向person表插入一条数据                                                *//************************************************************************/memset(sql, 0, sizeof(sql));strcpy(sql, "insert into sysdba.person(sex, name, email, phone) values(:sex,:name,:email,:phone)");// 准备SQL语句OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);// 设置输入参数memset(szsex, 0, sizeof(szsex));memcpy(szsex, "M", strlen("M") + 1);memset(szname, 0, sizeof(szname));memcpy(szname, "张三", strlen("张三") + 1);memset(szemail, 0, sizeof(szemail));memcpy(szemail, "zhangsan@dameng.com", strlen("zhangsan@dameng.com") + 1);memset(szphone, 0, sizeof(szphone));memcpy(szphone, "02712345678", strlen("02712345678") + 1);// 绑定输入列const OraText col_sex[] = ":sex";const OraText col_name[] = ":name";const OraText col_email[] = ":email";const OraText col_phone[] = ":phone";OCIBindByName(stmthp, &bidhp[0], errhp, col_sex, 4, szsex,strlen((char*)szsex), SQLT_AFC, NULL, NULL, NULL, 0, NULL, 0);OCIBindByName(stmthp, &bidhp[1], errhp, col_name, 5, szname,strlen((char*)szname), SQLT_AFC, NULL, NULL, NULL, 0, NULL, 0);OCIBindByName(stmthp, &bidhp[2], errhp, col_email, 6, szemail,strlen((char*)szemail), SQLT_AFC, NULL, NULL, NULL, 0, NULL, 0);OCIBindByName(stmthp, &bidhp[3], errhp, col_phone, 6, szphone,strlen((char*)szphone), SQLT_AFC, NULL, NULL, NULL, 0, NULL, 0);// 执行SQL语句ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0,(CONST OCISnapshot*) 0, (OCISnapshot*)0, (ub4)OCI_DEFAULT);if (ret != 0){OCIErrorGet(errhp, 1, NULL, &ret, (OraText*)errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);printf("\n%s\n", errbuf);}else{printf("\n新增了 name = 张三 的记录。\n");}// 提交到数据库OCITransCommit(svchp, errhp, OCI_DEFAULT);/************************************************************************//* 更新person表                                                         *//************************************************************************/memset(sql, 0, sizeof(sql));strcpy(sql, "update sysdba.person set sex='M',name='Liuhuan',email='12345678@qq.com',phone='13399990000' WHERE personid='1'");// 准备SQL语句      OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);// 执行SQL语句ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0,(CONST OCISnapshot*)0, (OCISnapshot*)0, (ub4)OCI_DEFAULT);if (ret != 0){OCIErrorGet(errhp, 1, NULL, &ret, (OraText*)errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);printf("\n%s\n", errbuf);}else{printf("\n更新了 personid = 1 的记录。\n");}// 提交到数据库OCITransCommit(svchp, errhp, OCI_DEFAULT);/************************************************************************//* 删除person表的ID为5的记录,首先要在数据库中存在这条记录             *//************************************************************************/memset(sql, 0, sizeof(sql));strcpy(sql, "delete from sysdba.person WHERE personid=:1");// 准备SQL语句OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);// 绑定输入参数memset(szpersonid, 0, sizeof(szpersonid));memcpy(szpersonid, "5", strlen("5") + 1);OCIBindByPos(stmthp, &bidhp[0], errhp, 1, szpersonid, strlen((char*)szpersonid),SQLT_AFC, NULL, NULL, NULL, 0, NULL, 0);// 执行SQL语句ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0,(CONST OCISnapshot*) 0, (OCISnapshot*)0, (ub4)OCI_DEFAULT);if (ret != 0){OCIErrorGet(errhp, 1, NULL, &ret, (OraText*)errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);printf("\n%s\n", errbuf);}else{printf("\n删除了 personid = 5 的记录。\n");}// 提交到数据库OCITransCommit(svchp, errhp, OCI_DEFAULT);/************************************************************************//* 再次查询person表                                                       *//************************************************************************/strcpy(sql, "select personid, name, phone from sysdba.person");// 准备SQL语句OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);// 绑定输出列OCIDefineByPos(stmthp, &defhp[0], errhp, 1, (ub1*)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*)szphone,sizeof(szphone), SQLT_STR, &ind[2], 0, 0, OCI_DEFAULT);// 执行SQL语句ret = OCIStmtExecute(svchp, stmthp, errhp, (ub4)0, 0, NULL, NULL, OCI_DEFAULT);if (ret != 0){OCIErrorGet(errhp, 1, NULL, &ret, (OraText*)errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);printf("\n%s\n", errbuf);}printf("\n%-10s%-10s%-10s\n", "PERSONID", "NAME", "PHONE");while ((OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)) != OCI_NO_DATA){printf("%-10s", szpersonid);printf("%-10s", szname);printf("%-10s\n", szphone);}//结束会话OCISessionEnd(svchp, errhp, authp, (ub4)0);//断开与数据库的连接OCIServerDetach(srvhp, errhp, OCI_DEFAULT);//释放OCI句柄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);system("pause");return 0;
}

四、项目引入所需的库

1. 引入头文件

右侧项目-点击头文件-添加,将压缩包中dmoci/include目录下的文件给添加进去

最终的效果如下

2. 引入资源文件

右侧项目-点击资源文件-添加现有项,将压缩包中dmoci/dmoci.lib文件给添加进去

五、配置项目

放到项目上,右键点击属性。

修改C++选项

1. 修改C++选项常规

  1. 点击C/C++
  2. 将最上方的配置修改为所有配置以及所有平台
  3. 附件包含目录,内容如下
D:\damba\dm8\include;D:\damba\win_64__dmdci\dmoci;D:\damba\win_64__dmdci\dmoci\include
  1. D:\damba\dm8\include; 其中D:\damba\dm8本机达梦安装目录,也就是引入达梦安装目录的include
  2. D:\damba\win_64__dmdci\dmoci;其中D:\damba\win_64__dmdci 本机dci压缩解压后的路径,给改了个名
  3. D:\damba\win_64__dmdci\dmoci\include;其实就是引入dci\dmoci的includer

如果不确定包对不对的可以看着我这个对照一下dll

2. 修改C++选项所有选项

  1. 点击C/C++ — 所有选项
  2. 将最上方的配置修改为所有配置以及所有平台
  3. 附件包含目录,内容如下
D:\damba\dm8\include;D:\damba\win_64__dmdci\dmoci;D:\damba\win_64__dmdci\dmoci\include

修改链接器配置

1.修改链接器配置常规

  1. 点击链接器-常规
  2. 将最上方的配置修改为所有配置以及所有平台
  3. 附件库目录,内容如下
D:\damba\dm8\include;D:\damba\win_64__dmdci\dmoci;D:\damba\win_64__dmdci\dmoci\include

2.修改链接器配置输入

  1. 点击链接器-输入
  2. 将最上方的配置修改为所有配置以及所有平台
  3. 附件依赖项,注意;分割
dmoci.lib;

六、运行项目

如果出现找不到动态库请参考Q&A

Q&A

1.编译时错误:LNK2019

原因有两个:

  1. 用的Dci的库不是资料包里面的,就导致自己引用的dci库没有这些方法,所以报错
  2. dci的库项目编译时没有加载到项目里,重新按照修改链接器配置的部分对照修改

2.运行时错误:找不到动态库

这是因为没有将动态库文件拷贝到操作系统库目录去,操作系统在自己的环境变量目录中找不到需要的文件。

因为我是window系统,所以就将压缩包中dmoci目录下的所有东西拷贝到C:\Windows\System32的目录下

注意:拷贝过程中会有两个文件提示是否覆盖,这里选否即可

C语言DCI(OCI)方式连接DM数据库相关推荐

  1. C语言ODBC方式连接DM数据库

    C语言ODBC方式连接DM数据库 一.安装 UNIX ODBC 下载 unixODBC 和 unixODBC-devel . 安装 unixODBC 和 unixODBC-devel. [root@R ...

  2. QT Create OCI方式连接达梦数据库

    QT OCI方式连接达梦数据库 一.背景 用户使用QT Create开发集成软件 OCI的方式连接数据库. 需要说明的是,本人非开发人员,所以在C++代码编写思路或者使用方式上难免有些低级操作,调试中 ...

  3. Linux下安装DM数据库及SrpingBoot+druid连接DM数据库

    本文安装使用 CentOS7 操作系统,为 x86_64 架构,安装步骤全部以命令行方式,安装过程为参考达梦官方文档后的总结.安装完成后使用SrpingBoot+druid连接DM数据库,使用Mave ...

  4. S+MySQL——3.使用ODBC方式连接MySQL数据库

    文章目录 引言 1. 建立一个MFC对话框项目 2. 控件布局 2.1 添加控件 2.2 引入List Control控件类 2.3 定义控件变量 2.4 添加按钮点击响应函数 2.4 初始化List ...

  5. 使用OLE DB方式连接常用数据库的连接字符串的设置

    使用OLE DB方式连接常用数据库的连接字符串的设置 SQL Server 使用 OLE DB 所设置的连接字符串: 标准连接方式 Provider=sqloledb;Data Source=data ...

  6. 使用ident认证方式连接postgres数据库

    使用ident认证方式连接postgres数据库 postgres支持多种用户认证方式 什么是ident服务 postgres支持ident认证的原理 实验验证 环境准备 实验设计 数据库端相关配置 ...

  7. c 连接mysql怎么增删改_C++ API方式连接mysql数据库实现增删改查

    这里复制的 http://www.bitscn.com/pdb/mysql/201407/226252.html 一.环境配置 1,装好mysql,新建一个C++控制台工程(从最简单的弄起,这个会了, ...

  8. 使用Java语言开发工具idea连接MySQL数据库的基本步骤及操作实例

    Java连接MySQL数据库并进行一些基本操作以及导入jar包的两种方式 其实,任何开发工具连接数据库无非就是三步:1.安装驱动.2.加载驱动,创建连接对象.3.创建对象操作游标.4.游标调用函数完成 ...

  9. java oci_java oracle oci方式连接

    Java程序连接oracle数据库时,用oci驱动要比用thin驱动性能好些.主要的区别是使用thin驱动时,不需要安装oracle的客户端,而使用oci时则要安装oracle的客户端. 从使用thi ...

最新文章

  1. Linux运维相关目录
  2. 转:Python 代码调试技巧
  3. C++中智能指针的设计和使用
  4. 编码设置导致了eclipse/myeclipse代码无法保存
  5. 【随机过程】随机过程之更新过程(2)
  6. 科大讯飞独家Founding赞助国际语音顶会,14篇论文被收录
  7. jwt 长度_跟我一起学.NetCore之WebApi接口裸奔有风险(Jwt)
  8. vs2017 安装Qt VS Tools ,新建项目没有Qt GUI Application选项 ,解决方法
  9. 用PS给证件照换底色
  10. 一个操作系统的实现(8)进程间通信
  11. 一家VC支持企业的发展轨迹——了解每次融资后股权和期权的变化,以及股份是如何被稀释的【转载】...
  12. 卡西欧计算机fx82cnx怎么玩游戏,卡西欧fx-82ES计算器乱码玩法问题
  13. 微信小程序约课_基于微信小程序的瑜伽馆约课系统设计
  14. python学习[第十五篇] 文件系统
  15. terrasolid纵向看点云
  16. solidworks装配体改为柔性_情人节非标设计大礼包(SolidWorks软件大揭秘)
  17. Python(五)——简单爬虫学习
  18. 小学信息技术 计算机的灵魂 软件 教案,人教版小学五年级下信息技术全册教案.doc...
  19. 沃顿商学院谈判课pdf_与您的公共云提供商进行谈判的3个技巧
  20. 微信小程序:如何在{{}}中使用函数?WXML+WXS

热门文章

  1. Java黑皮书课后题第6章:*6.39(几何:点的位置)编程练习题3.32显示如何测试一个点是否在一个有向直线的左侧、右侧或在直线上,编写一个程序,输入三个点p0p1p2,显示p2是否在直线p0p1
  2. Kruscal算法+并查集 求解最小生成树
  3. 学生信息链表,建立,插入,删除,遍历,查找,修改,最大(小)值,平均...
  4. .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)...
  5. Ubuntu mysql连接错误10060/10061的方法
  6. php学习_数组 2013.01.04
  7. [Python爬虫] 中文编码问题:raw_input输入、文件读取、变量比较等str、unicode、utf-8转换问题
  8. LeetCode Algorithm 面试题 16.10. 生存人数
  9. 37. Sudoku Solver
  10. Linux操作系统中Anaconda的安装