Wrap the MYSQL* again so we can:

1) let mysql_init/mysql_close take care of any/all allocation, thread state and freeing
2) for faster access to the encoding and active state variables for the connection
This commit is contained in:
Brian Lopez 2010-08-16 02:03:19 -07:00
parent 3239a449b9
commit cebf9af068
6 changed files with 51 additions and 38 deletions

View File

@ -14,11 +14,13 @@ static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
}
#define MARK_CONN_INACTIVE(conn) \
rb_iv_set(conn, "@active", Qfalse);
wrapper->active = 0;
#define GET_CLIENT(self) \
MYSQL * client; \
Data_Get_Struct(self, MYSQL, client);
mysql_client_wrapper *wrapper; \
MYSQL *client; \
Data_Get_Struct(self, mysql_client_wrapper, wrapper); \
client = &wrapper->client;
/*
* used to pass all arguments to mysql_real_connect while inside
@ -66,6 +68,13 @@ struct nogvl_send_query_args {
* - mysql_ssl_set()
*/
static void rb_mysql_client_mark(void * wrapper) {
mysql_client_wrapper * w = wrapper;
if (w) {
rb_gc_mark(w->encoding);
}
}
static VALUE rb_raise_mysql2_error(MYSQL *client) {
VALUE e = rb_exc_new2(cMysql2Error, mysql_error(client));
rb_funcall(e, intern_error_number_eql, 1, INT2NUM(mysql_errno(client)));
@ -78,7 +87,7 @@ static VALUE nogvl_init(void *ptr) {
MYSQL * client = (MYSQL *)ptr;
/* may initialize embedded server and read /etc/services off disk */
mysql_init(client);
client = mysql_init(NULL);
return client ? Qtrue : Qfalse;
}
@ -96,7 +105,8 @@ static VALUE nogvl_connect(void *ptr) {
}
static void rb_mysql_client_free(void * ptr) {
MYSQL * client = (MYSQL *)ptr;
mysql_client_wrapper * wrapper = (mysql_client_wrapper *)ptr;
MYSQL * client = &wrapper->client;
/*
* we'll send a QUIT message to the server, but that message is more of a
@ -129,15 +139,12 @@ static VALUE nogvl_close(void * ptr) {
}
static VALUE allocate(VALUE klass) {
MYSQL * client;
return Data_Make_Struct(
klass,
MYSQL,
NULL,
rb_mysql_client_free,
client
);
VALUE obj;
mysql_client_wrapper * wrapper;
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
wrapper->encoding = Qnil;
wrapper->active = 0;
return obj;
}
static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE port, VALUE database, VALUE socket) {
@ -237,7 +244,9 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
rb_iv_set(resultObj, "@query_options", rb_obj_dup(rb_iv_get(self, "@query_options")));
#ifdef HAVE_RUBY_ENCODING_H
rb_iv_set(resultObj, "@encoding", GET_ENCODING(self));
mysql2_result_wrapper * result_wrapper;
GetMysql2Result(resultObj, result_wrapper);
result_wrapper->encoding = wrapper->encoding;
#endif
return resultObj;
}
@ -247,18 +256,17 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
fd_set fdset;
int fd, retval;
int async = 0;
VALUE opts, defaults, active;
VALUE opts, defaults;
int(*selector)(int, fd_set *, fd_set *, fd_set *, struct timeval *) = NULL;
GET_CLIENT(self)
REQUIRE_OPEN_DB(client);
args.mysql = client;
active = rb_iv_get(self, "@active");
// see if this connection is still waiting on a result from a previous query
if (NIL_P(active) || active == Qfalse) {
if (wrapper->active == 0) {
// mark this connection active
rb_iv_set(self, "@active", Qtrue);
wrapper->active = 1;
} else {
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
}
@ -276,7 +284,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
}
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
// ensure the string is in the encoding the connection is expecting
args.sql = rb_str_export_to_enc(args.sql, conn_enc);
#endif
@ -323,7 +331,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
Check_Type(str, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
// ensure the string is in the encoding the connection is expecting
str = rb_str_export_to_enc(str, conn_enc);
#endif
@ -348,11 +356,12 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
}
}
static VALUE rb_mysql_client_info(RB_MYSQL_UNUSED VALUE self) {
static VALUE rb_mysql_client_info(VALUE self) {
VALUE version = rb_hash_new(), client_info;
GET_CLIENT(self);
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
#endif
rb_hash_aset(version, sym_id, LONG2NUM(mysql_get_client_version()));
@ -372,7 +381,7 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
GET_CLIENT(self)
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
#endif
REQUIRE_OPEN_DB(client);
@ -446,14 +455,13 @@ static VALUE set_charset_name(VALUE self, VALUE value) {
GET_CLIENT(self)
#ifdef HAVE_RUBY_ENCODING_H
VALUE new_encoding, old_encoding;
VALUE new_encoding;
new_encoding = rb_funcall(cMysql2Client, intern_encoding_from_charset, 1, value);
if (new_encoding == Qnil) {
rb_raise(cMysql2Error, "Unsupported charset: '%s'", RSTRING_PTR(value));
} else {
old_encoding = rb_iv_get(self, "@encoding");
if (old_encoding == Qnil) {
rb_iv_set(self, "@encoding", new_encoding);
if (wrapper->encoding == Qnil) {
wrapper->encoding = new_encoding;
}
}
#endif

View File

@ -31,4 +31,10 @@ rb_thread_blocking_region(
void init_mysql2_client();
typedef struct {
VALUE encoding;
short int active;
MYSQL client;
} mysql_client_wrapper;
#endif

View File

@ -29,7 +29,4 @@
#include <client.h>
#include <result.h>
#define GET_ENCODING(self) \
rb_iv_get(self, "@encoding")
#endif

View File

@ -20,6 +20,7 @@ static void rb_mysql_result_mark(void * wrapper) {
if (w) {
rb_gc_mark(w->fields);
rb_gc_mark(w->rows);
rb_gc_mark(w->encoding);
}
}
@ -65,7 +66,7 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
MYSQL_FIELD *field = NULL;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
#endif
field = mysql_fetch_field_direct(wrapper->result, idx);
@ -97,13 +98,14 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
unsigned int i = 0;
unsigned long * fieldLengths;
void * ptr;
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(GET_ENCODING(self));
#endif
GetMysql2Result(self, wrapper);
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding();
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
#endif
ptr = wrapper->result;
row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
if (row == NULL) {
@ -401,6 +403,7 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
wrapper->result = r;
wrapper->fields = Qnil;
wrapper->rows = Qnil;
wrapper->encoding = Qnil;
rb_obj_call_init(obj, 0, NULL);
return obj;
}

View File

@ -7,6 +7,7 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r);
typedef struct {
VALUE fields;
VALUE rows;
VALUE encoding;
unsigned int numberOfFields;
unsigned long numberOfRows;
unsigned long lastRowProcessed;

View File

@ -12,7 +12,6 @@ module Mysql2
def initialize(opts = {})
@query_options = @@default_query_options.dup
@active = false
init_connection
@ -21,7 +20,6 @@ module Mysql2
send(:"#{key}=", opts[key])
end
# force the encoding to utf8
@encoding = nil
self.charset_name = opts[:encoding] || 'utf8'
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))