/* ruby mysql module
* $Id: mysql.c 229 2008-06-20 07:44:04Z tommy $
*/
#include <ruby.h>
#ifndef RSTRING_PTR
#define RSTRING_PTR(str) RSTRING(str)->ptr
#endif
#ifndef RSTRING_LEN
#define RSTRING_LEN(str) RSTRING(str)->len
#endif
#ifndef HAVE_RB_STR_SET_LEN
#define rb_str_set_len(str, length) (RSTRING_LEN(str) = (length))
#endif
#ifdef HAVE_MYSQL_H
#include <mysql.h>
#include <errmsg.h>
#include <mysqld_error.h>
#else
#include <mysql/mysql.h>
#include <mysql/errmsg.h>
#include <mysql/mysqld_error.h>
#endif
#define MYSQL_RUBY_VERSION 20800
#define GC_STORE_RESULT_LIMIT 20
#if MYSQL_VERSION_ID < 32224
#define mysql_field_count mysql_num_fields
#endif
#define NILorSTRING(obj) (NIL_P(obj)? NULL: StringValuePtr(obj))
#define NILorINT(obj) (NIL_P(obj)? 0: NUM2INT(obj))
#define GetMysqlStruct(obj) (Check_Type(obj, T_DATA), (struct mysql*)DATA_PTR(obj))
#define GetHandler(obj) (Check_Type(obj, T_DATA), &(((struct mysql*)DATA_PTR(obj))->handler))
#define GetMysqlRes(obj) (Check_Type(obj, T_DATA), ((struct mysql_res*)DATA_PTR(obj))->res)
#define GetMysqlStmt(obj) (Check_Type(obj, T_DATA), ((struct mysql_stmt*)DATA_PTR(obj))->stmt)
VALUE cMysql;
VALUE cMysqlRes;
VALUE cMysqlField;
VALUE cMysqlStmt;
VALUE cMysqlRowOffset;
VALUE cMysqlTime;
VALUE eMysql;
static int store_result_count = 0;
struct mysql {
MYSQL handler;
char connection;
char query_with_result;
};
struct mysql_res {
MYSQL_RES* res;
char freed;
};
#if MYSQL_VERSION_ID >= 40101
struct mysql_stmt {
MYSQL_STMT *stmt;
char closed;
struct {
int n;
MYSQL_BIND *bind;
unsigned long *length;
MYSQL_TIME *buffer;
} param;
struct {
int n;
MYSQL_BIND *bind;
my_bool *is_null;
unsigned long *length;
} result;
MYSQL_RES *res;
};
#endif
/* free Mysql class object */
static void free_mysql(struct mysql* my)
{
if (my->connection == Qtrue)
mysql_close(&my->handler);
xfree(my);
}
static void free_mysqlres(struct mysql_res* resp)
{
if (resp->freed == Qfalse) {
mysql_free_result(resp->res);
store_result_count--;
}
xfree(resp);
}
#if MYSQL_VERSION_ID >= 40101
static void free_mysqlstmt_memory(struct mysql_stmt *s)
{
if (s->param.bind) {
xfree(s->param.bind);
s->param.bind = NULL;
}
if (s->param.length) {
xfree(s->param.length);
s->param.length = NULL;
}
if (s->param.buffer) {
xfree(s->param.buffer);
s->param.buffer = NULL;
}
s->param.n = 0;
if (s->res) {
mysql_free_result(s->res);
s->res = NULL;
}
if (s->result.bind) {
int i;
for (i = 0; i < s->result.n; i++) {
if (s->result.bind[i].buffer)
xfree(s->result.bind[i].buffer);
s->result.bind[i].buffer = NULL;
}
xfree(s->result.bind);
s->result.bind = NULL;
}
if (s->result.is_null) {
xfree(s->result.is_null);
s->result.is_null = NULL;
}
if (s->result.length) {
xfree(s->result.length);
s->result.length = NULL;
}
s->result.n = 0;
}
static void free_execute_memory(struct mysql_stmt *s)
{
if (s->res && s->result.bind) {
int i;
for (i = 0; i < s->result.n; i++) {
if (s->result.bind[i].buffer)
xfree(s->result.bind[i].buffer);
s->result.bind[i].buffer = NULL;
}
}
mysql_stmt_free_result(s->stmt);
}
static void free_mysqlstmt(struct mysql_stmt* s)
{
free_mysqlstmt_memory(s);
if (s->closed == Qfalse)
mysql_stmt_close(s->stmt);
if (s->res)
mysql_free_result(s->res);
xfree(s);
}
#endif
static void mysql_raise(MYSQL* m)
{
VALUE e = rb_exc_new2(eMysql, mysql_error(m));
rb_iv_set(e, "errno", INT2FIX(mysql_errno(m)));
#if MYSQL_VERSION_ID >= 40101
rb_iv_set(e, "sqlstate", rb_tainted_str_new2(mysql_sqlstate(m)));
#endif
rb_exc_raise(e);
}
static VALUE mysqlres2obj(MYSQL_RES* res)
{
VALUE obj;
struct mysql_res* resp;
obj = Data_Make_Struct(cMysqlRes, struct mysql_res, 0, free_mysqlres, resp);
rb_iv_set(obj, "colname", Qnil);
rb_iv_set(obj, "tblcolname", Qnil);
resp->res = res;
resp->freed = Qfalse;
rb_obj_call_init(obj, 0, NULL);
if (++store_result_count > GC_STORE_RESULT_LIMIT)
rb_gc();
return obj;
}
/* make Mysql::Field object */
static VALUE make_field_obj(MYSQL_FIELD* f)
{
VALUE obj;
if (f == NULL)
return Qnil;
obj = rb_obj_alloc(cMysqlField);
rb_iv_set(obj, "name", f->name? rb_str_freeze(rb_tainted_str_new2(f->name)): Qnil);
rb_iv_set(obj, "table", f->table? rb_str_freeze(rb_tainted_str_new2(f->table)): Qnil);
rb_iv_set(obj, "def", f->def? rb_str_freeze(rb_tainted_str_new2(f->def)): Qnil);
rb_iv_set(obj, "type", INT2NUM(f->type));
rb_iv_set(obj, "length", INT2NUM(f->length));
rb_iv_set(obj, "max_length", INT2NUM(f->max_length));
rb_iv_set(obj, "flags", INT2NUM(f->flags));
rb_iv_set(obj, "decimals", INT2NUM(f->decimals));
return obj;
}
/*-------------------------------
* Mysql class method
*/
/* init() */
static VALUE init(VALUE klass)
{
struct mysql* myp;
VALUE obj;
obj = Data_Make_Struct(klass, struct mysql, 0, free_mysql, myp);
mysql_init(&myp->handler);
myp->connection = Qfalse;
myp->query_with_result = Qtrue;
rb_obj_call_init(obj, 0, NULL);
return obj;
}
/* real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, sock=nil, flag=nil) */
static VALUE real_connect(int argc, VALUE* argv, VALUE klass)
{
VALUE host, user, passwd, db, port, sock, flag;
char *h, *u, *p, *d, *s;
unsigned int pp, f;
struct mysql* myp;
VALUE obj;
#if MYSQL_VERSION_ID >= 32200
rb_scan_args(argc, argv, "07", &host, &user, &passwd, &db, &port, &sock, &flag);
d = NILorSTRING(db);
f = NILorINT(flag);
#elif MYSQL_VERSION_ID >= 32115
rb_scan_args(argc, argv, "06", &host, &user, &passwd, &port, &sock, &flag);
f = NILorINT(flag);
#else
rb_scan_args(argc, argv, "05", &host, &user, &passwd, &port, &sock);
#endif
h = NILorSTRING(host);
u = NILorSTRING(user);
p = NILorSTRING(passwd);
pp = NILorINT(port);
s = NILorSTRING(sock);
obj = Data_Make_Struct(klass, struct mysql, 0, free_mysql, myp);
#if MYSQL_VERSION_ID >= 32200
mysql_init(&myp->handler);
if (mysql_real_connect(&myp->handler, h, u, p, d, pp, s, f) == NULL)
#elif MYSQL_VERSION_ID >= 32115
if (mysql_real_connect(&myp->handler, h, u, p, pp, s, f) == NULL)
#else
if (mysql_real_connect(&myp->handler, h, u, p, pp, s) == NULL)
#endif
mysql_raise(&myp->handler);
myp->handler.reconnect = 0;
myp->connection = Qtrue;
myp->query_with_result = Qtrue;
rb_obj_call_init(obj, argc, argv);
return obj;
}
/* escape_string(string) */
static VALUE escape_string(VALUE klass, VALUE str)
{
VALUE ret;
Check_Type(str, T_STRING);
ret = rb_str_new(0, (RSTRING_LEN(str))*2+1);
rb_str_set_len(ret, mysql_escape_string(RSTRING_PTR(ret), RSTRING_PTR(str), RSTRING_LEN(str)));
return ret;
}
/* client_info() */
static VALUE client_info(VALUE klass)
{
return rb_tainted_str_new2(mysql_get_client_info());
}
#if MYSQL_VERSION_ID >= 32332
/* my_debug(string) */
static VALUE my_debug(VALUE obj, VALUE str)
{
mysql_debug(StringValuePtr(str));
return obj;
}
#endif
#if MYSQL_VERSION_ID >= 40000
/* client_version() */
static VALUE client_version(VALUE obj)
{
return INT2NUM(mysql_get_client_version());
}
#endif
/*-------------------------------
* Mysql object method
*/
#if MYSQL_VERSION_ID >= 32200
/* real_connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, sock=nil, flag=nil) */
static VALUE real_connect2(int argc, VALUE* argv, VALUE obj)
{
VALUE host, user, passwd, db, port, sock, flag;
char *h, *u, *p, *d, *s;
unsigned int pp, f;
MYSQL* m = GetHandler(obj);
rb_scan_args(argc, argv, "07", &host, &user, &passwd, &db, &port, &sock, &flag);
d = NILorSTRING(db);
f = NILorINT(flag);
h = NILorSTRING(host);
u = NILorSTRING(user);
p = NILorSTRING(passwd);
pp = NILorINT(port);
s = NILorSTRING(sock);
if (mysql_real_conn
评论1
最新资源