Compare commits
23 Commits
Author | SHA1 | Date |
---|---|---|
John Bintz | b99e0a057a | |
Brian Lopez | 52f62c8b44 | |
Brian Lopez | 66f595a406 | |
dan sinclair | 5f6ff0d4a8 | |
Brian Lopez | 80697d11b2 | |
dan sinclair | dac2f02c9b | |
dan sinclair | 9d49728c30 | |
dj2 | c2e2f0c46c | |
Youhei Kondou | 550c68cade | |
Brian Lopez | d48846f13b | |
Brian Lopez | 99766a2303 | |
Brian Lopez | badc5e04e3 | |
Brian Lopez | 974a5658d6 | |
Brian Lopez | 60b8d061ac | |
Brian Lopez | 2b37ace3dc | |
Brian Lopez | 1057f976d0 | |
Brian Lopez | 90ddb63e52 | |
Brian Lopez | 426cff8adc | |
Brian Lopez | f79bf6261e | |
Brian Lopez | 05df9e312d | |
Brian Lopez | 60fd02ebe6 | |
Brian Lopez | 7e75f5ed4c | |
Anko painting | e7dcf37bd4 |
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,5 +1,17 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.2.6 (October 19th, 2010)
|
||||||
|
* version bump since the 0.2.5 win32 binary gems were broken
|
||||||
|
|
||||||
|
## 0.2.5 (October 19th, 2010)
|
||||||
|
* fixes for easier Win32 binary gem deployment for targeting 1.8 and 1.9 in the same gem
|
||||||
|
* refactor of connection checks and management to avoid race conditions with the GC/threading to prevent the unexpected loss of connections
|
||||||
|
* update the default flags during connection
|
||||||
|
* add support for setting wait_timeout on AR adapter
|
||||||
|
* upgrade to rspec2
|
||||||
|
* bugfix for an edge case where the GC would clean up a Mysql2::Client object before the underlying MYSQL pointer had been initialized
|
||||||
|
* fix to CFLAGS to allow compilation on SPARC with sunstudio compiler - Anko painting <anko.com+github@gmail.com>
|
||||||
|
|
||||||
## 0.2.4 (September 17th, 2010)
|
## 0.2.4 (September 17th, 2010)
|
||||||
* a few patches for win32 support from Luis Lavena - thanks man!
|
* a few patches for win32 support from Luis Lavena - thanks man!
|
||||||
* bugfix from Eric Wong to avoid a potential stack overflow during Mysql2::Client#escape
|
* bugfix from Eric Wong to avoid a potential stack overflow during Mysql2::Client#escape
|
||||||
|
|
|
@ -76,7 +76,7 @@ static void rb_mysql_client_mark(void * wrapper) {
|
||||||
|
|
||||||
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, UINT2NUM(mysql_errno(client)));
|
||||||
rb_funcall(e, intern_sql_state_eql, 1, rb_tainted_str_new2(mysql_sqlstate(client)));
|
rb_funcall(e, intern_sql_state_eql, 1, rb_tainted_str_new2(mysql_sqlstate(client)));
|
||||||
rb_exc_raise(e);
|
rb_exc_raise(e);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
|
@ -264,7 +264,7 @@ 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;
|
VALUE opts, defaults, read_timeout;
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(wrapper);
|
REQUIRE_OPEN_DB(wrapper);
|
||||||
|
@ -290,6 +290,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
||||||
opts = defaults;
|
opts = defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Check_Type(args.sql, T_STRING);
|
||||||
#ifdef HAVE_RUBY_ENCODING_H
|
#ifdef HAVE_RUBY_ENCODING_H
|
||||||
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
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
|
||||||
|
@ -302,6 +303,23 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
||||||
return rb_raise_mysql2_error(wrapper->client);
|
return rb_raise_mysql2_error(wrapper->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
read_timeout = rb_iv_get(self, "@read_timeout");
|
||||||
|
struct timeval tv;
|
||||||
|
struct timeval* tvp = NULL;
|
||||||
|
if (!NIL_P(read_timeout)) {
|
||||||
|
Check_Type(read_timeout, T_FIXNUM);
|
||||||
|
tvp = &tv;
|
||||||
|
long int sec = FIX2INT(read_timeout);
|
||||||
|
// TODO: support partial seconds?
|
||||||
|
// also, this check is here for sanity, we also check up in Ruby
|
||||||
|
if (sec >= 0) {
|
||||||
|
tvp->tv_sec = sec;
|
||||||
|
} else {
|
||||||
|
rb_raise(cMysql2Error, "read_timeout must be a positive integer, you passed %ld", sec);
|
||||||
|
}
|
||||||
|
tvp->tv_usec = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!async) {
|
if (!async) {
|
||||||
// the below code is largely from do_mysql
|
// the below code is largely from do_mysql
|
||||||
// http://github.com/datamapper/do
|
// http://github.com/datamapper/do
|
||||||
|
@ -310,7 +328,11 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
||||||
FD_ZERO(&fdset);
|
FD_ZERO(&fdset);
|
||||||
FD_SET(fd, &fdset);
|
FD_SET(fd, &fdset);
|
||||||
|
|
||||||
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, NULL);
|
retval = rb_thread_select(fd + 1, &fdset, NULL, NULL, tvp);
|
||||||
|
|
||||||
|
if (retval == 0) {
|
||||||
|
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
||||||
|
}
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
rb_sys_fail(0);
|
rb_sys_fail(0);
|
||||||
|
@ -516,20 +538,6 @@ static VALUE init_connection(VALUE self) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call-seq: client.create_statement # => Mysql2::Statement
|
|
||||||
*
|
|
||||||
* Create a new prepared statement.
|
|
||||||
*/
|
|
||||||
static VALUE create_statement(VALUE self) {
|
|
||||||
MYSQL * client;
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
|
|
||||||
Data_Get_Struct(self, MYSQL, client);
|
|
||||||
stmt = mysql_stmt_init(client);
|
|
||||||
|
|
||||||
return Data_Wrap_Struct(cMysql2Statement, 0, mysql_stmt_close, stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_mysql2_client() {
|
void init_mysql2_client() {
|
||||||
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
cMysql2Client = rb_define_class_under(mMysql2, "Client", rb_cObject);
|
||||||
|
|
||||||
|
@ -544,7 +552,6 @@ void init_mysql2_client() {
|
||||||
rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
|
rb_define_method(cMysql2Client, "async_result", rb_mysql_client_async_result, 0);
|
||||||
rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
|
rb_define_method(cMysql2Client, "last_id", rb_mysql_client_last_id, 0);
|
||||||
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
|
rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
|
||||||
rb_define_method(cMysql2Client, "create_statement", create_statement, 0);
|
|
||||||
|
|
||||||
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
rb_define_private_method(cMysql2Client, "reconnect=", set_reconnect, 1);
|
||||||
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
rb_define_private_method(cMysql2Client, "connect_timeout=", set_connect_timeout, 1);
|
||||||
|
|
|
@ -33,8 +33,8 @@ void init_mysql2_client();
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VALUE encoding;
|
VALUE encoding;
|
||||||
short int active;
|
char active;
|
||||||
short int closed;
|
char closed;
|
||||||
MYSQL *client;
|
MYSQL *client;
|
||||||
} mysql_client_wrapper;
|
} mysql_client_wrapper;
|
||||||
|
|
||||||
|
|
|
@ -57,9 +57,13 @@ end
|
||||||
asplode h unless have_header h
|
asplode h unless have_header h
|
||||||
end
|
end
|
||||||
|
|
||||||
unless RUBY_PLATFORM =~ /mswin/
|
unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
|
||||||
$CFLAGS << ' -Wall -funroll-loops'
|
$CFLAGS << ' -Wall -funroll-loops'
|
||||||
end
|
end
|
||||||
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
|
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
|
||||||
|
|
||||||
|
if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
|
||||||
|
$LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
|
||||||
|
end
|
||||||
|
|
||||||
create_makefile('mysql2/mysql2')
|
create_makefile('mysql2/mysql2')
|
||||||
|
|
|
@ -2,21 +2,6 @@
|
||||||
|
|
||||||
VALUE mMysql2, cMysql2Error;
|
VALUE mMysql2, cMysql2Error;
|
||||||
|
|
||||||
/* call-seq: client.create_statement # => Mysql2::Statement
|
|
||||||
*
|
|
||||||
* Create a new prepared statement.
|
|
||||||
*/
|
|
||||||
static VALUE create_statement(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL * client;
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
|
|
||||||
Data_Get_Struct(self, MYSQL, client);
|
|
||||||
stmt = mysql_stmt_init(client);
|
|
||||||
|
|
||||||
return Data_Wrap_Struct(cMysql2Statement, 0, mysql_stmt_close, stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ruby Extension initializer */
|
/* Ruby Extension initializer */
|
||||||
void Init_mysql2() {
|
void Init_mysql2() {
|
||||||
mMysql2 = rb_define_module("Mysql2");
|
mMysql2 = rb_define_module("Mysql2");
|
||||||
|
@ -24,5 +9,4 @@ void Init_mysql2() {
|
||||||
|
|
||||||
init_mysql2_client();
|
init_mysql2_client();
|
||||||
init_mysql2_result();
|
init_mysql2_result();
|
||||||
init_mysql2_statement();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,12 @@
|
||||||
#include <ruby.h>
|
#include <ruby.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#ifndef HAVE_UINT
|
||||||
|
#define HAVE_UINT
|
||||||
|
typedef unsigned short ushort;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_MYSQL_H
|
#ifdef HAVE_MYSQL_H
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include <mysql_com.h>
|
#include <mysql_com.h>
|
||||||
|
@ -28,6 +34,5 @@
|
||||||
|
|
||||||
#include <client.h>
|
#include <client.h>
|
||||||
#include <result.h>
|
#include <result.h>
|
||||||
#include <statement.h>
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -248,7 +248,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
||||||
val = rb_str_new(row[i], fieldLengths[i]);
|
val = rb_str_new(row[i], fieldLengths[i]);
|
||||||
#ifdef HAVE_RUBY_ENCODING_H
|
#ifdef HAVE_RUBY_ENCODING_H
|
||||||
// if binary flag is set, respect it's wishes
|
// if binary flag is set, respect it's wishes
|
||||||
if (fields[i].flags & BINARY_FLAG) {
|
if (fields[i].flags & BINARY_FLAG && fields[i].charsetnr == 63) {
|
||||||
rb_enc_associate(val, binaryEncoding);
|
rb_enc_associate(val, binaryEncoding);
|
||||||
} else {
|
} else {
|
||||||
// lookup the encoding configured on this field
|
// lookup the encoding configured on this field
|
||||||
|
|
|
@ -8,10 +8,10 @@ typedef struct {
|
||||||
VALUE fields;
|
VALUE fields;
|
||||||
VALUE rows;
|
VALUE rows;
|
||||||
VALUE encoding;
|
VALUE encoding;
|
||||||
long numberOfFields;
|
unsigned int numberOfFields;
|
||||||
unsigned long numberOfRows;
|
unsigned long numberOfRows;
|
||||||
unsigned long lastRowProcessed;
|
unsigned long lastRowProcessed;
|
||||||
short int resultFreed;
|
char resultFreed;
|
||||||
MYSQL_RES *result;
|
MYSQL_RES *result;
|
||||||
} mysql2_result_wrapper;
|
} mysql2_result_wrapper;
|
||||||
|
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
#include <mysql2_ext.h>
|
|
||||||
|
|
||||||
VALUE cMysql2Statement;
|
|
||||||
extern VALUE mMysql2, cMysql2Error;
|
|
||||||
|
|
||||||
/* call-seq: stmt.prepare(sql)
|
|
||||||
*
|
|
||||||
* Prepare +sql+ for execution
|
|
||||||
*/
|
|
||||||
static VALUE prepare(VALUE self, VALUE sql)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
|
|
||||||
if(mysql_stmt_prepare(stmt, StringValuePtr(sql), RSTRING_LEN(sql))) {
|
|
||||||
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call-seq: stmt.param_count # => 2
|
|
||||||
*
|
|
||||||
* Returns the number of parameters the prepared statement expects.
|
|
||||||
*/
|
|
||||||
static VALUE param_count(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
|
|
||||||
return ULL2NUM(mysql_stmt_param_count(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call-seq: stmt.field_count # => 2
|
|
||||||
*
|
|
||||||
* Returns the number of fields the prepared statement returns.
|
|
||||||
*/
|
|
||||||
static VALUE field_count(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
|
|
||||||
return UINT2NUM(mysql_stmt_field_count(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call-seq: stmt.execute
|
|
||||||
*
|
|
||||||
* Executes the current prepared statement, returns +stmt+.
|
|
||||||
*/
|
|
||||||
static VALUE execute(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
|
|
||||||
if(mysql_stmt_execute(stmt))
|
|
||||||
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call-seq: stmt.fields -> array
|
|
||||||
*
|
|
||||||
* Returns a list of fields that will be returned by this statement.
|
|
||||||
*/
|
|
||||||
static VALUE fields(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
MYSQL_FIELD * fields;
|
|
||||||
MYSQL_RES * metadata;
|
|
||||||
unsigned int field_count;
|
|
||||||
unsigned int i;
|
|
||||||
VALUE field_list;
|
|
||||||
VALUE cMysql2Field;
|
|
||||||
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
metadata = mysql_stmt_result_metadata(stmt);
|
|
||||||
fields = mysql_fetch_fields(metadata);
|
|
||||||
field_count = mysql_stmt_field_count(stmt);
|
|
||||||
field_list = rb_ary_new2((long)field_count);
|
|
||||||
|
|
||||||
cMysql2Field = rb_const_get(mMysql2, rb_intern("Field"));
|
|
||||||
|
|
||||||
for(i = 0; i < field_count; i++) {
|
|
||||||
VALUE argv[2];
|
|
||||||
VALUE field;
|
|
||||||
|
|
||||||
/* FIXME: encoding. Also, can this return null? */
|
|
||||||
argv[0] = rb_str_new2(fields[i].name);
|
|
||||||
argv[1] = INT2NUM(fields[i].type);
|
|
||||||
|
|
||||||
field = rb_class_new_instance(2, argv, cMysql2Field);
|
|
||||||
|
|
||||||
rb_ary_store(field_list, (long)i, field);
|
|
||||||
}
|
|
||||||
|
|
||||||
return field_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE each(VALUE self)
|
|
||||||
{
|
|
||||||
MYSQL_STMT * stmt;
|
|
||||||
MYSQL_FIELD * fields;
|
|
||||||
MYSQL_RES * metadata;
|
|
||||||
|
|
||||||
MYSQL_BIND * binds;
|
|
||||||
my_bool * is_null;
|
|
||||||
my_bool * error;
|
|
||||||
unsigned long * length;
|
|
||||||
int int_data;
|
|
||||||
MYSQL_TIME ts;
|
|
||||||
|
|
||||||
unsigned int field_count;
|
|
||||||
unsigned int i;
|
|
||||||
VALUE block;
|
|
||||||
|
|
||||||
Data_Get_Struct(self, MYSQL_STMT, stmt);
|
|
||||||
|
|
||||||
block = rb_block_proc();
|
|
||||||
metadata = mysql_stmt_result_metadata(stmt);
|
|
||||||
fields = mysql_fetch_fields(metadata);
|
|
||||||
field_count = mysql_stmt_field_count(stmt);
|
|
||||||
|
|
||||||
binds = xcalloc(field_count, sizeof(MYSQL_BIND));
|
|
||||||
is_null = xcalloc(field_count, sizeof(my_bool));
|
|
||||||
error = xcalloc(field_count, sizeof(my_bool));
|
|
||||||
length = xcalloc(field_count, sizeof(unsigned long));
|
|
||||||
|
|
||||||
for(i = 0; i < field_count; i++) {
|
|
||||||
switch(fields[i].type) {
|
|
||||||
case MYSQL_TYPE_LONGLONG:
|
|
||||||
binds[i].buffer_type = MYSQL_TYPE_LONG;
|
|
||||||
binds[i].buffer = (char *)&int_data;
|
|
||||||
break;
|
|
||||||
case MYSQL_TYPE_DATETIME:
|
|
||||||
binds[i].buffer_type = MYSQL_TYPE_DATETIME;
|
|
||||||
binds[i].buffer = (char *)&ts;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rb_raise(cMysql2Error, "unhandled mysql type: %d", fields[i].type);
|
|
||||||
}
|
|
||||||
|
|
||||||
binds[i].is_null = &is_null[i];
|
|
||||||
binds[i].length = &length[i];
|
|
||||||
binds[i].error = &error[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mysql_stmt_bind_result(stmt, binds)) {
|
|
||||||
xfree(binds);
|
|
||||||
xfree(is_null);
|
|
||||||
xfree(error);
|
|
||||||
xfree(length);
|
|
||||||
rb_raise(cMysql2Error, "%s", mysql_stmt_error(stmt));
|
|
||||||
}
|
|
||||||
|
|
||||||
while(!mysql_stmt_fetch(stmt)) {
|
|
||||||
VALUE row = rb_ary_new2((long)field_count);
|
|
||||||
|
|
||||||
for(i = 0; i < field_count; i++) {
|
|
||||||
VALUE column = Qnil;
|
|
||||||
switch(binds[i].buffer_type) {
|
|
||||||
case MYSQL_TYPE_LONG:
|
|
||||||
column = INT2NUM(int_data);
|
|
||||||
break;
|
|
||||||
/* FIXME: maybe we want to return a datetime in this case? */
|
|
||||||
case MYSQL_TYPE_DATETIME:
|
|
||||||
column = rb_funcall(rb_cTime,
|
|
||||||
rb_intern("mktime"), 6,
|
|
||||||
UINT2NUM(ts.year),
|
|
||||||
UINT2NUM(ts.month),
|
|
||||||
UINT2NUM(ts.day),
|
|
||||||
UINT2NUM(ts.hour),
|
|
||||||
UINT2NUM(ts.minute),
|
|
||||||
UINT2NUM(ts.second));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rb_raise(cMysql2Error, "unhandled buffer type: %d",
|
|
||||||
binds[i].buffer_type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rb_ary_store(row, (long)i, column);
|
|
||||||
}
|
|
||||||
rb_yield(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree(binds);
|
|
||||||
xfree(is_null);
|
|
||||||
xfree(error);
|
|
||||||
xfree(length);
|
|
||||||
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_mysql2_statement()
|
|
||||||
{
|
|
||||||
cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
|
|
||||||
|
|
||||||
rb_define_method(cMysql2Statement, "prepare", prepare, 1);
|
|
||||||
rb_define_method(cMysql2Statement, "param_count", param_count, 0);
|
|
||||||
rb_define_method(cMysql2Statement, "field_count", field_count, 0);
|
|
||||||
rb_define_method(cMysql2Statement, "execute", execute, 0);
|
|
||||||
rb_define_method(cMysql2Statement, "each", each, 0);
|
|
||||||
rb_define_method(cMysql2Statement, "fields", fields, 0);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
#ifndef MYSQL2_STATEMENT_H
|
|
||||||
#define MYSQL2_STATEMENT_H
|
|
||||||
|
|
||||||
extern VALUE cMysql2Statement;
|
|
||||||
|
|
||||||
void init_mysql2_statement();
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -35,7 +35,6 @@ module Mysql2
|
||||||
results = @client.async_result
|
results = @client.async_result
|
||||||
@deferable.succeed(results)
|
@deferable.succeed(results)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
puts e.backtrace.join("\n\t")
|
|
||||||
@deferable.fail(e)
|
@deferable.fail(e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,6 +18,9 @@ module ActiveRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
module ConnectionAdapters
|
module ConnectionAdapters
|
||||||
|
class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
|
||||||
|
end
|
||||||
|
|
||||||
class Mysql2Column < Column
|
class Mysql2Column < Column
|
||||||
BOOL = "tinyint(1)"
|
BOOL = "tinyint(1)"
|
||||||
def extract_default(default)
|
def extract_default(default)
|
||||||
|
@ -447,7 +450,7 @@ module ActiveRecord
|
||||||
if current_index != row[:Key_name]
|
if current_index != row[:Key_name]
|
||||||
next if row[:Key_name] == PRIMARY # skip the primary key
|
next if row[:Key_name] == PRIMARY # skip the primary key
|
||||||
current_index = row[:Key_name]
|
current_index = row[:Key_name]
|
||||||
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
|
indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], [])
|
||||||
end
|
end
|
||||||
|
|
||||||
indexes.last.columns << row[:Column_name]
|
indexes.last.columns << row[:Column_name]
|
||||||
|
@ -622,8 +625,9 @@ module ActiveRecord
|
||||||
variable_assignments << "NAMES '#{encoding}'" if encoding
|
variable_assignments << "NAMES '#{encoding}'" if encoding
|
||||||
|
|
||||||
# increase timeout so mysql server doesn't disconnect us
|
# increase timeout so mysql server doesn't disconnect us
|
||||||
wait_timeout = @config[:wait_timeout] || 2592000
|
wait_timeout = @config[:wait_timeout]
|
||||||
variable_assignments << "@@wait_timeout = #{wait_timeout}" if wait_timeout.is_a?(Fixnum)
|
wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum)
|
||||||
|
variable_assignments << "@@wait_timeout = #{wait_timeout}"
|
||||||
|
|
||||||
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
|
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,11 +7,10 @@ require 'mysql2/error'
|
||||||
require 'mysql2/mysql2'
|
require 'mysql2/mysql2'
|
||||||
require 'mysql2/client'
|
require 'mysql2/client'
|
||||||
require 'mysql2/result'
|
require 'mysql2/result'
|
||||||
require 'mysql2/field'
|
|
||||||
|
|
||||||
# = Mysql2
|
# = Mysql2
|
||||||
#
|
#
|
||||||
# A modern, simple and very fast Mysql library for Ruby - binding to libmysql
|
# A modern, simple and very fast Mysql library for Ruby - binding to libmysql
|
||||||
module Mysql2
|
module Mysql2
|
||||||
VERSION = "0.2.4"
|
VERSION = "0.2.6"
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,6 +24,11 @@ module Mysql2
|
||||||
# force the encoding to utf8
|
# force the encoding to utf8
|
||||||
self.charset_name = opts[:encoding] || 'utf8'
|
self.charset_name = opts[:encoding] || 'utf8'
|
||||||
|
|
||||||
|
@read_timeout = opts[:read_timeout]
|
||||||
|
if @read_timeout and @read_timeout < 0
|
||||||
|
raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
|
||||||
|
end
|
||||||
|
|
||||||
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
|
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslciper))
|
||||||
|
|
||||||
user = opts[:username]
|
user = opts[:username]
|
||||||
|
|
|
@ -23,10 +23,14 @@ module Mysql2
|
||||||
end
|
end
|
||||||
|
|
||||||
def query(sql, opts={})
|
def query(sql, opts={})
|
||||||
super(sql, opts.merge(:async => true))
|
if ::EM.reactor_running?
|
||||||
deferable = ::EM::DefaultDeferrable.new
|
super(sql, opts.merge(:async => true))
|
||||||
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
|
deferable = ::EM::DefaultDeferrable.new
|
||||||
deferable
|
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
|
||||||
|
deferable
|
||||||
|
else
|
||||||
|
super(sql, opts)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
require 'mysql2/em'
|
||||||
|
require 'fiber'
|
||||||
|
|
||||||
|
module Mysql2
|
||||||
|
module EM
|
||||||
|
module Fiber
|
||||||
|
class Client < ::Mysql2::EM::Client
|
||||||
|
def query(sql, opts={})
|
||||||
|
if ::EM.reactor_running?
|
||||||
|
deferable = super(sql, opts)
|
||||||
|
|
||||||
|
fiber = ::Fiber.current
|
||||||
|
deferable.callback do |result|
|
||||||
|
fiber.resume(result)
|
||||||
|
end
|
||||||
|
deferable.errback do |err|
|
||||||
|
fiber.resume(err)
|
||||||
|
end
|
||||||
|
::Fiber.yield
|
||||||
|
else
|
||||||
|
super(sql, opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +0,0 @@
|
||||||
module Mysql2
|
|
||||||
class Field < Struct.new(:name, :type)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = %q{mysql2}
|
s.name = %q{mysql2}
|
||||||
s.version = "0.2.4"
|
s.version = "0.2.6"
|
||||||
|
|
||||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
s.authors = ["Brian Lopez"]
|
s.authors = ["Brian Lopez"]
|
||||||
s.date = %q{2010-10-18}
|
s.date = %q{2010-10-19}
|
||||||
s.email = %q{seniorlopez@gmail.com}
|
s.email = %q{seniorlopez@gmail.com}
|
||||||
s.extensions = ["ext/mysql2/extconf.rb"]
|
s.extensions = ["ext/mysql2/extconf.rb"]
|
||||||
s.extra_rdoc_files = [
|
s.extra_rdoc_files = [
|
||||||
|
@ -46,6 +46,7 @@ Gem::Specification.new do |s|
|
||||||
"lib/mysql2.rb",
|
"lib/mysql2.rb",
|
||||||
"lib/mysql2/client.rb",
|
"lib/mysql2/client.rb",
|
||||||
"lib/mysql2/em.rb",
|
"lib/mysql2/em.rb",
|
||||||
|
"lib/mysql2/em_fiber.rb",
|
||||||
"lib/mysql2/error.rb",
|
"lib/mysql2/error.rb",
|
||||||
"lib/mysql2/result.rb",
|
"lib/mysql2/result.rb",
|
||||||
"mysql2.gemspec",
|
"mysql2.gemspec",
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# encoding: UTF-8
|
||||||
|
if defined? EventMachine && defined? Fiber
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'mysql2/em_fiber'
|
||||||
|
|
||||||
|
describe Mysql2::EM::Fiber::Client do
|
||||||
|
it 'should support queries' do
|
||||||
|
results = []
|
||||||
|
EM.run do
|
||||||
|
Fiber.new {
|
||||||
|
client1 = Mysql2::EM::Fiber::Client.new
|
||||||
|
results = client1.query "SELECT sleep(0.1) as first_query"
|
||||||
|
EM.stop_event_loop
|
||||||
|
}.resume
|
||||||
|
end
|
||||||
|
|
||||||
|
results.first.keys.should include("first_query")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "Either EventMachine or Fibers not available. Skipping tests that use them."
|
||||||
|
end
|
|
@ -85,7 +85,19 @@ describe Mysql2::Client do
|
||||||
@client.should respond_to(:query)
|
@client.should respond_to(:query)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should expect read_timeout to be a positive integer" do
|
||||||
|
lambda {
|
||||||
|
Mysql2::Client.new(:read_timeout => -1)
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
end
|
||||||
|
|
||||||
context "#query" do
|
context "#query" do
|
||||||
|
it "should only accept strings as the query parameter" do
|
||||||
|
lambda {
|
||||||
|
@client.query ["SELECT 'not right'"]
|
||||||
|
}.should raise_error(TypeError)
|
||||||
|
end
|
||||||
|
|
||||||
it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
|
it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
|
||||||
@client.query "SELECT 1", :something => :else
|
@client.query "SELECT 1", :something => :else
|
||||||
@client.query_options.should eql(@client.query_options.merge(:something => :else))
|
@client.query_options.should eql(@client.query_options.merge(:something => :else))
|
||||||
|
@ -118,6 +130,13 @@ describe Mysql2::Client do
|
||||||
}.should raise_error(Mysql2::Error)
|
}.should raise_error(Mysql2::Error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should timeout if we wait longer than :read_timeout" do
|
||||||
|
client = Mysql2::Client.new(:read_timeout => 1)
|
||||||
|
lambda {
|
||||||
|
client.query("SELECT sleep(2)")
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
end
|
||||||
|
|
||||||
# XXX this test is not deterministic (because Unix signal handling is not)
|
# XXX this test is not deterministic (because Unix signal handling is not)
|
||||||
# and may fail on a loaded system
|
# and may fail on a loaded system
|
||||||
if RUBY_PLATFORM !~ /mingw|mswin/
|
if RUBY_PLATFORM !~ /mingw|mswin/
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
# encoding: UTF-8
|
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe Mysql2::Statement do
|
|
||||||
before :each do
|
|
||||||
@client = Mysql2::Client.new :host => "localhost", :username => "root"
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should create a statement" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.should be_kind_of Mysql2::Statement
|
|
||||||
end
|
|
||||||
|
|
||||||
it "prepares some sql" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
lambda { stmt.prepare 'SELECT 1' }.should_not raise_error
|
|
||||||
end
|
|
||||||
|
|
||||||
it "return self when prepare some sql" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare('SELECT 1').should == stmt
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an exception when server disconnects" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
@client.close
|
|
||||||
lambda { stmt.prepare 'SELECT 1' }.should raise_error(Mysql2::Error)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should tell us the param count" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT ?, ?'
|
|
||||||
stmt.param_count.should == 2
|
|
||||||
|
|
||||||
stmt.prepare 'SELECT 1'
|
|
||||||
stmt.param_count.should == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should tell us the field count" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT ?, ?'
|
|
||||||
stmt.field_count.should == 2
|
|
||||||
|
|
||||||
stmt.prepare 'SELECT 1'
|
|
||||||
stmt.field_count.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should let us execute our statement" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT 1'
|
|
||||||
stmt.execute.should == stmt
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an exception on error" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
lambda { stmt.execute }.should raise_error(Mysql2::Error)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should raise an exception without a block" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT 1'
|
|
||||||
stmt.execute
|
|
||||||
lambda { stmt.each }.should raise_error
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should let us iterate over results" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT 1'
|
|
||||||
stmt.execute
|
|
||||||
rows = []
|
|
||||||
stmt.each { |row| rows << row }
|
|
||||||
rows.should == [[1]]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should select dates" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT NOW()'
|
|
||||||
stmt.execute
|
|
||||||
rows = []
|
|
||||||
stmt.each { |row| rows << row }
|
|
||||||
rows.first.first.should be_kind_of Time
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should tell us about the fields" do
|
|
||||||
stmt = @client.create_statement
|
|
||||||
stmt.prepare 'SELECT 1 as foo, 2'
|
|
||||||
stmt.execute
|
|
||||||
list = stmt.fields
|
|
||||||
list.length.should == 2
|
|
||||||
list.first.name.should == 'foo'
|
|
||||||
list[1].name.should == '2'
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue