mysql sqlca_mysql:C源代码内嵌SQL语句的预编译工具

本文介绍了在C语言环境中操作MySQL数据库时,如何使用预编译工具e2mysql替代JDBC。文章详细阐述了使用e2mysql进行预处理、编译过程中的问题及解决方案,包括头文件缺失、类型不识别等问题,并提供了github源代码链接。
摘要由CSDN通过智能技术生成

本文较水 哪篇不水

今天遇到一个比较好玩的东西,记下来跟大家分享。

我们知道操作数据库,在JAVA环境中一般会使用JDBC,不管是mysql、oracle还是别的什么数据库都可以比较好的支持;但在一些比较古老(或者说比较谨慎)的系统中,比如银行业,可能其应用使用的还是C语言写的,这种情况JDBC是没门了,只能调用对应数据库提供的C lib,例如mysql的C库提供了这些接口:

MYSQL *mysql_init(MYSQL *mysql)

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)

int mysql_query(MYSQL *mysql, const char *stmt_str)

有了C库,按照一般的思路,直接在C里面调用对应的API就好了,但显然这样不如直接写SQL方便。于是像Oracle就提供了[ProC](http://baike.baidu.com/link?url=GeQqyf0TdG0m3EWrFIVO7LIw8yUsjzAFA7E4VKm_s21kOWD2rePSmVCKCyUWT5GGdKm-v8EJ8U0HWZMZGmlv8K)这种工具。

说白了PRO*C就是一种预编译工具,我们写的代码是C和SQL混合的,这样的代码没办法直接编译,gcc不认。PROC会将该代码(.pc)转为纯C代码,这样就可以用gcc编译为可执行文件了。但PROC是为ORACLE服务的,编译出来的代码调用的也是ORACLE的C库,显然我们想给mysql用是行不通的,需要一款类似的工具。其他的数据库,如IBM DB2有PREP,Informix和Postgre SQL Server都有自己的ESQL/C工具。

在网上扒了半天,找到了这么一个工具,open esql。下载下来解压后看到两个文件夹,e2odbc是使用ODBC,理论上应该适应所有类型的数据库,而e2mysql是我们要用的。进到e2mysql看到有三个文件:e2mysql.awk e2mysql.cpp e2mysql.h。e2mysql.awk是一个awk脚本,用来预处理pc混合文件;e2mysql.cpp用来定义数据库连接信息。

使用步骤如下:

1、使用awk脚本转换pc文件为C++文件。

# awk -f e2mysql.awk xxx.pc > xxx.cpp

预处理实际就是文本转换处理,正是awk的用武之地。

2、将xxx.cpp与e2mysql.cpp一起编译。

# g++ xxx.cpp e2mysql.cpp -o xxx `mysql_config --cflags --libs`

步骤很简单,但过程中遇到了一些问题,这里记一下,您自己解决起来应该也比较简单。

1、g++编译的时候提示没有sqlda.h、sqlcpr.h。

xxx.cpp:7:21: error: sqlda.h: No such file or directory

xxx.cpp:8:20: warning: extra tokens at end of #include directive

xxx.cpp:8:22: error: sqlcpr.h: No such file or directory

PRO*C的源文件里会调用这两个头文件,我们没有,删掉即可。如果是在生产环境,建议创建这两个头文件,为空即可。

2、提示e2mysql.h里没有定义strlen。

e2mysql.h: In function ‘int32_t SQLBindParmPoly(std::string&, const char*, char, uint16_t)’:

e2mysql.h:176: error: ‘strlen’ was not declared in this scope

strlen是C的string函数,需要包含cstring头文件:#include 。

3、提示e2mysql.h里没有定义atoi。

e2mysql.h: In function ‘int32_t SQLBindColPoly(const char*, int16_t&, uint16_t)’:

e2mysql.h:319: error: ‘atoi’ was not declared in this scope

atoi是stdlib里的函数,需要包含该头文件:#include 。

4、提示EXEC不识别。

xxx.cpp:13: error: ‘EXEC’ does not name a type

找到代码里是这一句:

/*RELEASE_CURSOR=YES 使PROC 在执行完后释放与嵌入SQL有关资源*/

EXEC ORACLE OPTION (RELEASE_CURSOR = YES);

显然这句是跟ORACLE相关的,工具不认。我这里粗暴的将这句注释掉了。

5、提示使用了int16类型不识别。

xxx.cpp:33: error: ‘int16’ does not name a type

xxx.cpp:61: error: ‘int16’ does not name a type

xxx.cpp:78: error: ‘int16’ does not name a type

应该是作者的环境不是gcc,而是一些能认int16这种变体的windows环境。这个是在awk预编译的时候生成的,需要改awk脚本源码,我这里是整体替换为了short int。

6、提示sqlca_struct里没有sqlerrm。

xxx.cpp: In function ‘void sql_error(char*)’:

xxx.cpp:92: error: ‘struct sqlca_struct’ has no member named ‘sqlerrm’

如上,sqlca是oracle特有的,这儿不识别,注释掉即可。

7、编译成功,执行的时候提示连不上'abc.xyz.com'。

看了下awk脚本,没有对connect做转换,而e2mysql.cpp里有个SQLHelperConnect(void)函数,里面可以修改数据库连接信息,改之,重新编译,验证OK。

# ./xxx

Connecting to database

Connected: testc1=100,c2=200,c3=300

mysql> select * from xxx;

+------+------+------+

| c1 | c2 | c3 |

+------+------+------+

| 100 | 200 | 300 |

+------+------+------+

1 row inset (0.00 sec)

8、如果提示没有mysql.h,或者找不到mysqlclient的lib,建议安装mysql-devel(centos 6.5),并且在编译的时候,不要手工指定-I、-L、-lmysqlclient,而是用mysql_config自动配置:mysql_config --cflags --libs。

总的来说这个脚本在不复杂的情况下还是能用的,但确实不成熟,如果有大量的C文件,需要一个一个去转,而且每个文件可能都要做一些修改;没能像PRO*C那样可以返回SQL执行的结果,用户用起来不方便;等等。解决问题的思路没错,但如果要商业化,还是有很长的路要走。

所有源文件放到github上了,参见open-esql-s。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值