2016年2月22日月曜日

MySQLを動的にリンクする

久しぶりにデータベースの勉強をしようと思い僕のWindowsマシンにMySQLを入れてみました。
ところがMySQLをC言語から使おうとするとVisualStudio2013までしかサポートしていません。
せっかく最新のVisualStudio2015をいれたのに。これでは最新の開発でMySQL使えないじゃん。

このようなVisualStudioやGCCのバージョン依存問題って本当によく起こるのでこれらを解決する方法を考えてみました。

考えること一時間、MySQLの関数を動的にリンクして呼び出せばよいのではないかと思い、MySQLの動的呼び出しラッパーをつくってみました。

余談ですが、MySQLのコード書いている人、とても正しくきれいにコーディングできていてすごいですね。びっくりです。OpenSSLなんて汚くて汚くて。


mysql_wrapper.h
----------------------------------------
#ifndef MY_SQL_WRAPPER_H_
#define MY_SQL_WRAPPER_H_

#include <mysql/mysql.h>

#ifdef __cplusplus
extern "C"
{
#endif

extern MYSQL * (STDCALL *pf_mysql_init)(MYSQL *mysql);
extern void (STDCALL *pf_mysql_close)(MYSQL *sock);
extern MYSQL * (STDCALL *pf_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 clientflag);
extern int (STDCALL *pf_mysql_query)(MYSQL *mysql, const char *q);
extern MYSQL_RES * (STDCALL *pf_mysql_use_result)(MYSQL *mysql);
extern void (STDCALL *pf_mysql_free_result)(MYSQL_RES *result);
extern MYSQL_ROW(STDCALL *pf_mysql_fetch_row)(MYSQL_RES *result);


#ifdef __cplusplus
}
#endif

#ifndef MY_SQL_WRAOPPER_C

#define mysql_init pf_mysql_init
#define mysql_close pf_mysql_close
#define mysql_real_connect pf_mysql_real_connect
#define mysql_query pf_mysql_query
#define mysql_use_result pf_mysql_use_result
#define mysql_free_result pf_mysql_free_result
#define mysql_fetch_row pf_mysql_fetch_row

#endif /* MY_SQL_WRAOPPER_C */

#endif /* MY_SQL_WRAPPER_H_ */
----------------------------------------


mysql_wrapper.cpp
----------------------------------------
#define MY_SQL_WRAOPPER_C
#include "mysql_wrapper.h"
#include "dll_client.h"

MYSQL * (STDCALL *pf_mysql_init)(MYSQL *mysql)=NULL;
void (STDCALL *pf_mysql_close)(MYSQL *sock)=NULL;
MYSQL * (STDCALL *pf_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 clientflag) = NULL;
int (STDCALL *pf_mysql_query)(MYSQL *mysql, const char *q)=NULL;
MYSQL_RES * (STDCALL *pf_mysql_use_result)(MYSQL *mysql)=NULL;
void (STDCALL *pf_mysql_free_result)(MYSQL_RES *result)=NULL;
MYSQL_ROW(STDCALL *pf_mysql_fetch_row)(MYSQL_RES *result) = NULL;


static void *h_mysql = NULL;

class mysql_wrapper {
public :
mysql_wrapper();
virtual ~mysql_wrapper();
};

mysql_wrapper::mysql_wrapper()
{
h_mysql = dll_load(DLL_NAME("libmysql"));
if (h_mysql == NULL)return;
pf_mysql_init = (MYSQL * (STDCALL *)(MYSQL *))dll_access(h_mysql, "mysql_init");
pf_mysql_close = (void (STDCALL *)(MYSQL *))dll_access(h_mysql, "mysql_close");
pf_mysql_real_connect = (MYSQL * (STDCALL *)(MYSQL *, const char *,
const char *, const char *, const char *, unsigned int ,
const char *, unsigned long))dll_access(h_mysql, "mysql_real_connect");
pf_mysql_query = (int (STDCALL *)(MYSQL *mysql, const char *))dll_access(h_mysql, "mysql_query");
pf_mysql_use_result = (MYSQL_RES * (STDCALL *)(MYSQL *))dll_access(h_mysql, "mysql_use_result");
pf_mysql_free_result = (void (STDCALL *)(MYSQL_RES *))dll_access(h_mysql, "mysql_free_result");
pf_mysql_fetch_row = (MYSQL_ROW(STDCALL*)(MYSQL_RES *))dll_access(h_mysql, "mysql_fetch_row");
}

mysql_wrapper::~mysql_wrapper()
{
if (h_mysql)dll_close(h_mysql);
h_mysql = NULL;
}


static mysql_wrapper s_mysql_wrapper;




----------------------------------------

test.c
----------------------------------------
#define I_USE_MYSQL_WRAPPER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef I_USE_MYSQL_WRAPPER
#include "mysql_wrapper.h"
#else
#include <mysql/mysql.h>
#endif


int main(void) {
MYSQL *conn = NULL;
MYSQL_RES *resp = NULL;
MYSQL_ROW row;
char sql_str[255];
char *sql_serv = "localhost";
char *user = "root";
char *passwd = "hoge";
char *db_name = "db_test";

memset(&sql_str[0], 0x00, sizeof(sql_str));

// mysql接続
conn = mysql_init(NULL);

if (!mysql_real_connect(conn, sql_serv, user, passwd, db_name, 0, NULL, 0)) {
// error
exit(-1);
}

// クエリ実行
snprintf(&sql_str[0], sizeof(sql_str) - 1, "select * from tb_test");
if (mysql_query(conn, &sql_str[0])) {
// error
mysql_close(conn);
exit(-1);
}

// レスポンス
resp = mysql_use_result(conn);

while ((row = mysql_fetch_row(resp)) != NULL) {
printf("%d : %s\n", atoi(row[0]), row[1]);
}

// 後片づけ
mysql_free_result(resp);
mysql_close(conn);
return 0;
}

----------------------------------------

やったー、動いた。
テストプログラムもちゃんと動きました。

この方法、OpenCVなどC++で書かれているライブラリだと使えませんが、
OpenSSLなどC言語で書かれているほかのライブラリでも使えます。

0 件のコメント:

コメントを投稿