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

View File

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

View File

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

View File

@ -20,6 +20,7 @@ static void rb_mysql_result_mark(void * wrapper) {
if (w) { if (w) {
rb_gc_mark(w->fields); rb_gc_mark(w->fields);
rb_gc_mark(w->rows); 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; MYSQL_FIELD *field = NULL;
#ifdef HAVE_RUBY_ENCODING_H #ifdef HAVE_RUBY_ENCODING_H
rb_encoding *default_internal_enc = rb_default_internal_encoding(); 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 #endif
field = mysql_fetch_field_direct(wrapper->result, idx); 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 int i = 0;
unsigned long * fieldLengths; unsigned long * fieldLengths;
void * ptr; 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); 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; ptr = wrapper->result;
row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0); row = (MYSQL_ROW)rb_thread_blocking_region(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
if (row == NULL) { if (row == NULL) {
@ -401,6 +403,7 @@ VALUE rb_mysql_result_to_obj(MYSQL_RES * r) {
wrapper->result = r; wrapper->result = r;
wrapper->fields = Qnil; wrapper->fields = Qnil;
wrapper->rows = Qnil; wrapper->rows = Qnil;
wrapper->encoding = Qnil;
rb_obj_call_init(obj, 0, NULL); rb_obj_call_init(obj, 0, NULL);
return obj; return obj;
} }

View File

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

View File

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