23,124
社区成员
发帖
与我相关
我的任务
分享
static ngx_int_t
ngx_dbd_mysql_close(ngx_dbd_t *dbd)
{
if (dbd->res) {
ngx_dbd_mysql_free_result(dbd->res);
}
if (dbd->tran) {
ngx_dbd_mysql_end_tran(dbd->tran);
}
if (dbd->mysql) {
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"mysql_close(%p)", dbd->mysql);
mysql_close(dbd->mysql);
dbd->mysql = NULL;
}
return NGX_OK;
}
static void *
ngx_dbd_mysql_native_handle(ngx_dbd_t *dbd)
{
return dbd->mysql;
}
static ngx_int_t
ngx_dbd_mysql_check_conn(ngx_dbd_t *dbd)
{
if (mysql_ping(dbd->mysql) != 0) {
ngx_log_error(NGX_LOG_ALERT, dbd->log, 0,
"mysql_ping(%p) failed (%ud: %s)",
dbd->mysql,
mysql_errno(dbd->mysql), mysql_error(dbd->mysql));
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"mysql_ping(%p)", dbd->mysql);
return NGX_OK;
}
static ngx_int_t
ngx_dbd_mysql_select_db(ngx_dbd_t *dbd, u_char *dbname)
{
if (mysql_select_db(dbd->mysql, (const char *) dbname) != 0) {
ngx_log_error(NGX_LOG_ALERT, dbd->log, 0,
"mysql_select_db(%p, \"%s\") failed (%ud: %s)",
dbd->mysql, dbname,
mysql_errno(dbd->mysql), mysql_error(dbd->mysql));
return NGX_ERROR;
}
ngx_log_debug2(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"mysql_select_db(%p, \"%s\")", dbd->mysql, dbname);
return NGX_OK;
}
static ngx_dbd_tran_t *
ngx_dbd_mysql_start_tran(ngx_dbd_t *dbd)
{
ngx_dbd_tran_t *tran;
tran = dbd->tran;
if (tran && tran->dbd) {
return tran;
}
if (dbd->res) {
ngx_dbd_mysql_free_result(dbd->res);
}
/* disable auto-commit */
if (mysql_autocommit(dbd->mysql, 0) != 0) {
ngx_log_error(NGX_LOG_ALERT, dbd->log, 0,
"mysql_autocommit(%p, 0) failed (%ud: %s)",
dbd->mysql,
mysql_errno(dbd->mysql), mysql_error(dbd->mysql));
return NULL;
}
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"mysql_autocommit(%p, 0)", dbd->mysql);
if (tran == NULL) {
tran = ngx_palloc(dbd->pool, sizeof(ngx_dbd_tran_t));
if (tran == NULL) {
return NULL;
}
dbd->tran = tran;
}
tran->dbd = dbd;
tran->mode = NGX_DBD_TRANS_MODE_COMMIT;
return tran;
}
static ngx_int_t
ngx_dbd_mysql_end_tran(ngx_dbd_tran_t *tran)
{
int rc;
u_char *name;
ngx_dbd_t *dbd;
dbd = tran->dbd;
if (dbd == NULL) {
return NGX_OK;
}
if (dbd->res) {
ngx_dbd_mysql_free_result(dbd->res);
}
/* commit or rollback transaction */
if (NGX_DBD_TRANS_DO_COMMIT(tran)) {
name = (u_char *) "mysql_commit";
rc = mysql_commit(dbd->mysql);
} else {
name = (u_char *) "mysql_rollback";
rc = mysql_rollback(dbd->mysql);
}
if (rc != 0) {
ngx_log_error(NGX_LOG_ALERT, dbd->log, 0, "%s(%p) failed (%ud: %s)",
name, dbd->mysql,
mysql_errno(dbd->mysql), mysql_error(dbd->mysql));
return NGX_ERROR;
}
ngx_log_debug2(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"%s(%p)", name, dbd->mysql);
/* enable auto-commit */
if (mysql_autocommit(dbd->mysql, 1) != 0) {
ngx_log_error(NGX_LOG_ALERT, dbd->log, 0,
"mysql_autocommit(%p, 1) failed (%ud: %s)",
dbd->mysql, mysql_errno(dbd->mysql),
mysql_error(dbd->mysql));
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, dbd->log, 0,
"mysql_autocommit(%p, 1)", dbd->mysql);
tran->dbd = NULL;
return NGX_OK;
}
static ngx_uint_t
ngx_dbd_mysql_get_tran_mode(ngx_dbd_tran_t *tran)
{
if (tran == NULL) {
return NGX_DBD_TRANS_MODE_COMMIT;
}
return tran->mode;
}
static ngx_dbd_t *
ngx_dbd_mysql_open(ngx_pool_t *pool, ngx_str_t *conn_str, ngx_log_t *log)
{
MYSQL *mysql;
u_char *host, *user, *pass, *dbname, *sock, *group;
ngx_dbd_t *dbd;
ngx_uint_t n, i, port, flags, fldsz;
ngx_array_t *params;
ngx_keyval_t *kv;
#if MYSQL_VERSION_ID >= 50013
my_bool reconnect;
#endif
#if (NGX_DEBUG)
MY_CHARSET_INFO csi;
#endif
/* parse connection string */
params = ngx_p2sp_parse_str(conn_str, NGX_P2SP_PARSE_COPY_STR, pool);
if (params == NULL) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"invalid connection string: \"%V\"", conn_str);
return NULL;
}
host = NULL;
user = NULL;
pass = NULL;
dbname = NULL;
sock = NULL;
group = NULL;
port = 3306;
flags = CLIENT_MULTI_STATEMENTS;
fldsz = NGX_DBD_MYSQL_FIELDSIZE;
kv = params->elts;
n = params->nelts;
for (i = 0; i < n; i++) {
if (ngx_strncmp(kv[i].key.data, "host", kv[0].key.len) == 0) {
host = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "user", kv[i].key.len) == 0) {
user = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "passwd", kv[i].key.len) == 0) {
pass = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "dbname", kv[i].key.len) == 0) {
dbname = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "sock", kv[i].key.len) == 0) {
sock = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "group", kv[i].key.len) == 0) {
group = kv[i].value.data;
} else if (ngx_strncmp(kv[i].key.data, "port", kv[i].key.len) == 0) {
port = ngx_atoi(kv[i].value.data, kv[i].value.len);
} else if (ngx_strncmp(kv[i].key.data, "flags", kv[i].key.len) == 0) {
if (ngx_strstrn(kv[i].value.data, "CLIENT_FOUND_ROWS",
kv[i].value.len))
{
flags |= CLIENT_FOUND_ROWS;
}
} else if (ngx_strncmp(kv[i].key.data, "fldsz", kv[i].key.len) == 0) {
fldsz = ngx_atoi(kv[i].value.data, kv[i].value.len);
} else {
/* TODO */
}
}
mysql = mysql_init(NULL);
if (mysql == NULL) {
return NULL;
}
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0, "mysql_init: %p", mysql);
if (group) {
if (mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, group) != 0) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"mysql_options(MYSQL_READ_DEFAULT_GROUP, "
"\"%s\") failed", group);
}
}
#if MYSQL_VERSION_ID >= 50013
reconnect = 1;
if (mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"mysql_options(MYSQL_OPT_RECONNECT, %ui) failed",
reconnect);
}
#endif
if (mysql_real_connect(mysql, (const char *) host, user, pass, dbname,
(unsigned int) port, sock, (unsigned int) flags)
== NULL)
{
ngx_log_error(NGX_LOG_ALERT, log, 0,
"mysql_real_connect(\"%V\") failed (%ud: %s)",
conn_str, mysql_errno(mysql), mysql_error(mysql));
mysql_close(mysql);
return NULL;
}
ngx_log_debug2(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_real_connect(\"%V\") %p", conn_str, mysql);
/* TODO: 设置连接使用的字符集,外部可通过在连接字符串中指定 */
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_character_set_name: %s",
mysql_character_set_name(mysql));
#if 0
if (mysql_set_character_set(mysql, "gb2312") != 0) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
"mysql_set_character_set(%p, \"gb2312\") "
"failed (%ud: %s)",
mysql, mysql_errno(mysql), mysql_error(mysql));
} else {
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_set_character_set(%p, \"gb2312\")", mysql);
}
#endif
#if (NGX_DEBUG)
mysql_get_character_set_info(mysql, &csi);
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"character set number: %ud", csi.number);
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"character set state: %ud", csi.state);
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"character set name: %s", csi.name);
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"collation name: %s", csi.csname);
/*ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"comment: %s", csi.comment ? csi.comment : "NULL");*/
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"character set directory: %s", csi.dir ? csi.dir : "NULL");
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"multibyte strings min length: %ud", csi.mbminlen);
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"multibyte strings max length: %ud", csi.mbmaxlen);
#endif
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_get_host_info: %s", mysql_get_host_info(mysql));
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_get_proto_info: %ud", mysql_get_proto_info(mysql));
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_get_server_info: %s", mysql_get_server_info(mysql));
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_get_server_version: %ul",
mysql_get_server_version(mysql));
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, log, 0,
"mysql_stat: %s", mysql_stat(mysql));
dbd = ngx_palloc(pool, sizeof(ngx_dbd_t));
if (dbd == NULL) {
mysql_close(mysql);
return NULL;
}
dbd->mysql = mysql;
dbd->log = log;
dbd->pool = pool;
dbd->fldsz = fldsz;
dbd->res = NULL;
dbd->tran = NULL;
dbd->escaped.data = NULL;
dbd->escaped.len = 0;
return dbd;
}
/*
* Copyright (C) ngwsx
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_dbd.h>
#include <ngx_p2sp.h>
#if (NGX_DBD_MYSQL)
#include <mysql/mysql.h>
static ngx_int_t ngx_dbd_mysql_init(ngx_cycle_t *cycle);
static void ngx_dbd_mysql_done(ngx_cycle_t *cycle);
static ngx_dbd_t *ngx_dbd_mysql_open(ngx_pool_t *pool, ngx_str_t *conn_str,
ngx_log_t *log);
static ngx_int_t ngx_dbd_mysql_close(ngx_dbd_t *dbd);
static void *ngx_dbd_mysql_native_handle(ngx_dbd_t *dbd);
static ngx_int_t ngx_dbd_mysql_check_conn(ngx_dbd_t *dbd);
static ngx_int_t ngx_dbd_mysql_select_db(ngx_dbd_t *dbd, u_char *dbname);
static ngx_dbd_tran_t *ngx_dbd_mysql_start_tran(ngx_dbd_t *dbd);
static ngx_int_t ngx_dbd_mysql_end_tran(ngx_dbd_tran_t *tran);
static ngx_uint_t ngx_dbd_mysql_get_tran_mode(ngx_dbd_tran_t *tran);
static ngx_uint_t ngx_dbd_mysql_set_tran_mode(ngx_dbd_tran_t *tran,
ngx_uint_t mode);
static ngx_int_t ngx_dbd_mysql_exec(ngx_dbd_t *dbd, u_char *sql,
int *affected);
static ngx_dbd_res_t *ngx_dbd_mysql_query(ngx_dbd_t *dbd, u_char *sql,
ngx_uint_t random);
static int ngx_dbd_mysql_num_fields(ngx_dbd_res_t *res);
static int ngx_dbd_mysql_num_rows(ngx_dbd_res_t *res);
static const ngx_str_t *ngx_dbd_mysql_field_name(ngx_dbd_res_t *res, int col);
static ngx_dbd_row_t *ngx_dbd_mysql_fetch_row(ngx_dbd_res_t *res, int row);
static const ngx_str_t *ngx_dbd_mysql_fetch_field(ngx_dbd_row_t *row, int col);
static ngx_int_t ngx_dbd_mysql_datum_get(ngx_dbd_row_t *row, int col,
ngx_dbd_type_e type, void *data);
static const u_char *ngx_dbd_mysql_escape(ngx_dbd_t *dbd, const u_char *str);
static int ngx_dbd_mysql_errno(ngx_dbd_t *dbd);
static const u_char *ngx_dbd_mysql_strerror(ngx_dbd_t *dbd);
static ngx_str_t ngx_dbd_mysql_name = ngx_string("mysql");
static ngx_dbd_module_t ngx_dbd_mysql_module_ctx = {
NULL,
NULL,
{ &ngx_dbd_mysql_name,
ngx_dbd_mysql_init,
ngx_dbd_mysql_done,
ngx_dbd_mysql_open,
ngx_dbd_mysql_close,
ngx_dbd_mysql_native_handle,
ngx_dbd_mysql_check_conn,
ngx_dbd_mysql_select_db,
ngx_dbd_mysql_start_tran,
ngx_dbd_mysql_end_tran,
ngx_dbd_mysql_get_tran_mode,
ngx_dbd_mysql_set_tran_mode,
ngx_dbd_mysql_exec,
ngx_dbd_mysql_query,
ngx_dbd_mysql_num_fields,
ngx_dbd_mysql_num_rows,
ngx_dbd_mysql_field_name,
ngx_dbd_mysql_fetch_row,
ngx_dbd_mysql_fetch_field,
ngx_dbd_mysql_datum_get,
ngx_dbd_mysql_escape,
ngx_dbd_mysql_errno,
ngx_dbd_mysql_strerror }
};
ngx_module_t ngx_dbd_mysql_module = {
NGX_MODULE_V1,
&ngx_dbd_mysql_module_ctx, /* module context */
NULL, /* module directives */
NGX_DBD_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
/* default maximum field size 1MB */
#define NGX_DBD_MYSQL_FIELDSIZE 1048575
struct ngx_dbd_s {
MYSQL *mysql;
ngx_uint_t fldsz;
ngx_str_t escaped;
ngx_dbd_res_t *res;
ngx_dbd_tran_t *tran;
ngx_log_t *log;
ngx_pool_t *pool;
};
struct ngx_dbd_tran_s {
ngx_uint_t mode;
ngx_dbd_t *dbd;
};
struct ngx_dbd_res_s {
MYSQL_RES *res;
MYSQL_STMT *stmt;
ngx_uint_t random;
ngx_str_t field_name;
ngx_dbd_row_t *row;
ngx_dbd_t *dbd;
};
struct ngx_dbd_row_s {
MYSQL_ROW row;
ngx_uint_t *lengths;
ngx_str_t field;
ngx_dbd_res_t *res;
};
static void
ngx_dbd_mysql_free_result(ngx_dbd_res_t *res)
{
if (res->res == NULL) {
return;
}
if (!res->random) {
while (mysql_fetch_row(res->res)) {}
}
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, res->dbd->log, 0,
"mysql_free_result(%p)", res->res);
mysql_free_result(res->res);
res->res = NULL;
}
static ngx_int_t
ngx_dbd_mysql_init(ngx_cycle_t *cycle)
{
if (mysql_library_init(0, NULL, NULL) != 0) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"mysql_library_init() failed");
return NGX_ERROR;
}
ngx_log_debug0(NGX_LOG_DEBUG_MYSQL, cycle->log, 0, "mysql_library_init()");
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, cycle->log, 0,
"mysql_get_client_info: %s", mysql_get_client_info());
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, cycle->log, 0,
"mysql_get_client_version: %ul", mysql_get_client_version());
ngx_log_debug1(NGX_LOG_DEBUG_MYSQL, cycle->log, 0,
"mysql_thread_safe: %ud", mysql_thread_safe());
return NGX_OK;
}
static void
ngx_dbd_mysql_done(ngx_cycle_t *cycle)
{
mysql_thread_end();
ngx_log_debug0(NGX_LOG_DEBUG_MYSQL, cycle->log, 0, "mysql_thread_end()");
mysql_library_end();
ngx_log_debug0(NGX_LOG_DEBUG_MYSQL, cycle->log, 0, "mysql_library_end()");
}