Compare commits
50 Commits
static-lin
...
master
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 | |
Brian Lopez | 0b3b63305e | |
Brian Lopez | 47405ae1f0 | |
Brian Lopez | a8041fed21 | |
Brian Lopez | e823b9ec0d | |
Brian Lopez | c8020f29ac | |
Brian Lopez | 3c6959a8bb | |
Brian Lopez | 410e914411 | |
Brian Lopez | 3b6229771a | |
Brian Lopez | 0ae583fe64 | |
Brian Lopez | 22c9ff48a8 | |
Brian Lopez | 0a7e7ee475 | |
Brian Lopez | ba4f3612b6 | |
Brian Lopez | 841ee2bba4 | |
Brian Lopez | 6e5cda6a52 | |
Brian Lopez | 832eb2d247 | |
Brian Lopez | c394122fd9 | |
Brian Lopez | a6b5e9c28c | |
Brian Lopez | 7169649857 | |
Brian Lopez | 225ddadaf7 | |
Brian Lopez | 0d1e9916bf | |
Brian Lopez | a17ba07c75 | |
Brian Lopez | f9d30e8f85 | |
Brian Lopez | 40f0cd012c | |
Anton Mironov | 687487d5a5 | |
Brian Lopez | 2ae908c512 | |
Brian Lopez | 4383885634 | |
Brian Lopez | 307b92b966 |
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
|
||||||
|
|
|
@ -234,7 +234,7 @@ then iterating over every row using an #each like method yielding a block:
|
||||||
|
|
||||||
== Special Thanks
|
== Special Thanks
|
||||||
|
|
||||||
* Eric Wong - for the contribution (and informative explanations of) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
|
* Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
|
||||||
* Yury Korolev (http://github.com/yury) - for TONS of help testing the ActiveRecord adapter
|
* Yury Korolev (http://github.com/yury) - for TONS of help testing the ActiveRecord adapter
|
||||||
* Aaron Patterson (http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
|
* Aaron Patterson (http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
|
||||||
* Mike Perham (http://github.com/mperham) - Async ActiveRecord adapter (uses Fibers and EventMachine)
|
* Mike Perham (http://github.com/mperham) - Async ActiveRecord adapter (uses Fibers and EventMachine)
|
||||||
|
|
37
Rakefile
37
Rakefile
|
@ -1,42 +1,5 @@
|
||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
begin
|
|
||||||
require 'jeweler'
|
|
||||||
JEWELER = Jeweler::Tasks.new do |gem|
|
|
||||||
gem.name = "mysql2"
|
|
||||||
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
|
|
||||||
gem.email = "seniorlopez@gmail.com"
|
|
||||||
gem.homepage = "http://github.com/brianmario/mysql2"
|
|
||||||
gem.authors = ["Brian Lopez"]
|
|
||||||
gem.require_paths = ["lib", "ext"]
|
|
||||||
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
|
|
||||||
gem.files = `git ls-files`.split("\n")
|
|
||||||
gem.extensions = ["ext/mysql2/extconf.rb"]
|
|
||||||
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
|
|
||||||
# gem.rubyforge_project = "mysql2"
|
|
||||||
end
|
|
||||||
rescue LoadError
|
|
||||||
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler -s http://gems.github.com"
|
|
||||||
end
|
|
||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'spec/rake/spectask'
|
|
||||||
|
|
||||||
desc "Run all examples with RCov"
|
|
||||||
Spec::Rake::SpecTask.new('spec:rcov') do |t|
|
|
||||||
t.spec_files = FileList['spec/']
|
|
||||||
t.rcov = true
|
|
||||||
t.rcov_opts = lambda do
|
|
||||||
IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Spec::Rake::SpecTask.new('spec') do |t|
|
|
||||||
t.spec_files = FileList['spec/']
|
|
||||||
t.spec_opts << '--options' << 'spec/spec.opts'
|
|
||||||
t.verbose = true
|
|
||||||
t.warning = true
|
|
||||||
end
|
|
||||||
|
|
||||||
task :default => :spec
|
|
||||||
|
|
||||||
# Load custom tasks
|
# Load custom tasks
|
||||||
Dir['tasks/*.rake'].sort.each { |f| load f }
|
Dir['tasks/*.rake'].sort.each { |f| load f }
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
# encoding: UTF-8
|
|
||||||
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
|
||||||
|
|
||||||
require 'rubygems'
|
|
||||||
require 'benchmark'
|
|
||||||
require 'mysql2'
|
|
||||||
|
|
||||||
iterations = 1000
|
|
||||||
client = Mysql2::Client.new(:host => "localhost", :username => "root", :database => "test")
|
|
||||||
query = lambda{ iterations.times{ client.query("SELECT mysql2_test.* FROM mysql2_test") } }
|
|
||||||
Benchmark.bmbm do |x|
|
|
||||||
x.report('select') do
|
|
||||||
query.call
|
|
||||||
end
|
|
||||||
x.report('rb_thread_select') do
|
|
||||||
thread = Thread.new{ sleep(10) }
|
|
||||||
query.call
|
|
||||||
thread.kill
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -9,7 +9,7 @@ static ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
|
||||||
static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
|
static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
|
||||||
|
|
||||||
#define REQUIRE_OPEN_DB(wrapper) \
|
#define REQUIRE_OPEN_DB(wrapper) \
|
||||||
if(wrapper->closed || !wrapper->client->net.vio) { \
|
if(wrapper->closed) { \
|
||||||
rb_raise(cMysql2Error, "closed MySQL connection"); \
|
rb_raise(cMysql2Error, "closed MySQL connection"); \
|
||||||
return Qnil; \
|
return Qnil; \
|
||||||
}
|
}
|
||||||
|
@ -76,18 +76,18 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE nogvl_init(void *ptr) {
|
static VALUE nogvl_init(void *ptr) {
|
||||||
MYSQL **client = (MYSQL **)ptr;
|
MYSQL *client;
|
||||||
|
|
||||||
/* may initialize embedded server and read /etc/services off disk */
|
/* may initialize embedded server and read /etc/services off disk */
|
||||||
*client = mysql_init(NULL);
|
client = mysql_init((MYSQL *)ptr);
|
||||||
return *client ? Qtrue : Qfalse;
|
return client ? Qtrue : Qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE nogvl_connect(void *ptr) {
|
static VALUE nogvl_connect(void *ptr) {
|
||||||
|
@ -104,45 +104,42 @@ static VALUE nogvl_connect(void *ptr) {
|
||||||
return client ? Qtrue : Qfalse;
|
return client ? Qtrue : Qfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rb_mysql_client_free(void * ptr) {
|
static VALUE nogvl_close(void *ptr) {
|
||||||
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
mysql_client_wrapper *wrapper = ptr;
|
||||||
|
if (!wrapper->closed) {
|
||||||
|
wrapper->closed = 1;
|
||||||
|
|
||||||
/*
|
|
||||||
* we'll send a QUIT message to the server, but that message is more of a
|
|
||||||
* formality than a hard requirement since the socket is getting shutdown
|
|
||||||
* anyways, so ensure the socket write does not block our interpreter
|
|
||||||
*/
|
|
||||||
int fd = wrapper->client->net.fd;
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
|
||||||
/*
|
/*
|
||||||
|
* we'll send a QUIT message to the server, but that message is more of a
|
||||||
|
* formality than a hard requirement since the socket is getting shutdown
|
||||||
|
* anyways, so ensure the socket write does not block our interpreter
|
||||||
|
*
|
||||||
|
*
|
||||||
* if the socket is dead we have no chance of blocking,
|
* if the socket is dead we have no chance of blocking,
|
||||||
* so ignore any potential fcntl errors since they don't matter
|
* so ignore any potential fcntl errors since they don't matter
|
||||||
*/
|
*/
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int flags = fcntl(fd, F_GETFL);
|
int flags = fcntl(wrapper->client->net.fd, F_GETFL);
|
||||||
if (flags > 0 && !(flags & O_NONBLOCK))
|
if (flags > 0 && !(flags & O_NONBLOCK))
|
||||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
fcntl(wrapper->client->net.fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
#else
|
#else
|
||||||
u_long iMode = 1;
|
u_long iMode = 1;
|
||||||
ioctlsocket(fd, FIONBIO, &iMode);
|
ioctlsocket(wrapper->client->net.fd, FIONBIO, &iMode);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
mysql_close(wrapper->client);
|
||||||
|
free(wrapper->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's safe to call mysql_close() on an already closed connection. */
|
return Qnil;
|
||||||
if (!wrapper->closed) {
|
|
||||||
mysql_close(wrapper->client);
|
|
||||||
}
|
|
||||||
xfree(ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE nogvl_close(void * ptr) {
|
static void rb_mysql_client_free(void * ptr) {
|
||||||
mysql_client_wrapper *wrapper = ptr;
|
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
||||||
if (!wrapper->closed) {
|
|
||||||
mysql_close(wrapper->client);
|
nogvl_close(wrapper);
|
||||||
wrapper->closed = 1;
|
|
||||||
}
|
xfree(ptr);
|
||||||
return Qnil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE allocate(VALUE klass) {
|
static VALUE allocate(VALUE klass) {
|
||||||
|
@ -151,7 +148,8 @@ static VALUE allocate(VALUE klass) {
|
||||||
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
||||||
wrapper->encoding = Qnil;
|
wrapper->encoding = Qnil;
|
||||||
wrapper->active = 0;
|
wrapper->active = 0;
|
||||||
wrapper->closed = 0;
|
wrapper->closed = 1;
|
||||||
|
wrapper->client = (MYSQL*)malloc(sizeof(MYSQL));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +164,7 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
||||||
args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
|
args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
|
||||||
args.db = NIL_P(database) ? NULL : StringValuePtr(database);
|
args.db = NIL_P(database) ? NULL : StringValuePtr(database);
|
||||||
args.mysql = wrapper->client;
|
args.mysql = wrapper->client;
|
||||||
args.client_flag = NUM2INT(flags);
|
args.client_flag = NUM2ULONG(flags);
|
||||||
|
|
||||||
if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
|
if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
|
||||||
// unable to connect
|
// unable to connect
|
||||||
|
@ -185,7 +183,9 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
||||||
static VALUE rb_mysql_client_close(VALUE self) {
|
static VALUE rb_mysql_client_close(VALUE self) {
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
|
||||||
rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
if (!wrapper->closed) {
|
||||||
|
rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -334,6 +356,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
||||||
unsigned long newLen, oldLen;
|
unsigned long newLen, oldLen;
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
|
||||||
|
REQUIRE_OPEN_DB(wrapper);
|
||||||
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();
|
||||||
|
@ -345,7 +368,6 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
||||||
oldLen = RSTRING_LEN(str);
|
oldLen = RSTRING_LEN(str);
|
||||||
newStr = rb_str_new(0, oldLen*2+1);
|
newStr = rb_str_new(0, oldLen*2+1);
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(wrapper);
|
|
||||||
newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
|
newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
|
||||||
if (newLen == oldLen) {
|
if (newLen == oldLen) {
|
||||||
// no need to return a new ruby string if nothing changed
|
// no need to return a new ruby string if nothing changed
|
||||||
|
@ -365,6 +387,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
||||||
static VALUE rb_mysql_client_info(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);
|
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(wrapper->encoding);
|
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
||||||
|
@ -385,13 +408,13 @@ static VALUE rb_mysql_client_info(VALUE self) {
|
||||||
static VALUE rb_mysql_client_server_info(VALUE self) {
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
||||||
VALUE version, server_info;
|
VALUE version, server_info;
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
|
||||||
|
REQUIRE_OPEN_DB(wrapper);
|
||||||
#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(wrapper->encoding);
|
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(wrapper);
|
|
||||||
|
|
||||||
version = rb_hash_new();
|
version = rb_hash_new();
|
||||||
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
||||||
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
||||||
|
@ -419,8 +442,14 @@ static VALUE rb_mysql_client_last_id(VALUE self) {
|
||||||
|
|
||||||
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
my_ulonglong retVal;
|
||||||
|
|
||||||
REQUIRE_OPEN_DB(wrapper);
|
REQUIRE_OPEN_DB(wrapper);
|
||||||
return ULL2NUM(mysql_affected_rows(wrapper->client));
|
retVal = mysql_affected_rows(wrapper->client);
|
||||||
|
if (retVal == (my_ulonglong)-1) {
|
||||||
|
rb_raise_mysql2_error(wrapper->client);
|
||||||
|
}
|
||||||
|
return ULL2NUM(retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE set_reconnect(VALUE self, VALUE value) {
|
static VALUE set_reconnect(VALUE self, VALUE value) {
|
||||||
|
@ -500,11 +529,12 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE
|
||||||
static VALUE init_connection(VALUE self) {
|
static VALUE init_connection(VALUE self) {
|
||||||
GET_CLIENT(self);
|
GET_CLIENT(self);
|
||||||
|
|
||||||
if (rb_thread_blocking_region(nogvl_init, ((void *) &wrapper->client), RUBY_UBF_IO, 0) == Qfalse) {
|
if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
||||||
/* TODO: warning - not enough memory? */
|
/* TODO: warning - not enough memory? */
|
||||||
return rb_raise_mysql2_error(wrapper->client);
|
return rb_raise_mysql2_error(wrapper->client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wrapper->closed = 0;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
@ -617,8 +620,15 @@ module ActiveRecord
|
||||||
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
||||||
variable_assignments = ['SQL_AUTO_IS_NULL=0']
|
variable_assignments = ['SQL_AUTO_IS_NULL=0']
|
||||||
encoding = @config[:encoding]
|
encoding = @config[:encoding]
|
||||||
|
|
||||||
|
# make sure we set the encoding
|
||||||
variable_assignments << "NAMES '#{encoding}'" if encoding
|
variable_assignments << "NAMES '#{encoding}'" if encoding
|
||||||
|
|
||||||
|
# increase timeout so mysql server doesn't disconnect us
|
||||||
|
wait_timeout = @config[:wait_timeout]
|
||||||
|
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
|
||||||
|
|
||||||
|
|
|
@ -12,5 +12,5 @@ require 'mysql2/result'
|
||||||
#
|
#
|
||||||
# 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
|
||||||
|
|
|
@ -8,7 +8,8 @@ module Mysql2
|
||||||
:symbolize_keys => false, # return field names as symbols instead of strings
|
:symbolize_keys => false, # return field names as symbols instead of strings
|
||||||
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
|
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
|
||||||
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
|
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
|
||||||
:cache_rows => true # tells Mysql2 to use it's internal row cache for results
|
:cache_rows => true, # tells Mysql2 to use it's internal row cache for results
|
||||||
|
:connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION
|
||||||
}
|
}
|
||||||
|
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
|
@ -23,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]
|
||||||
|
@ -31,7 +37,7 @@ module Mysql2
|
||||||
port = opts[:port] || 3306
|
port = opts[:port] || 3306
|
||||||
database = opts[:database]
|
database = opts[:database]
|
||||||
socket = opts[:socket]
|
socket = opts[:socket]
|
||||||
flags = opts[:flags] || 0
|
flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
|
||||||
|
|
||||||
connect user, pass, host, port, database, socket, flags
|
connect user, pass, host, port, database, socket, flags
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,20 +13,24 @@ module Mysql2
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_readable
|
def notify_readable
|
||||||
|
detach
|
||||||
begin
|
begin
|
||||||
@deferable.succeed(@client.async_result)
|
@deferable.succeed(@client.async_result)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
@deferable.fail(e)
|
@deferable.fail(e)
|
||||||
end
|
end
|
||||||
detach
|
|
||||||
end
|
end
|
||||||
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
|
|
@ -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-09-17}
|
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 = [
|
||||||
|
@ -17,6 +17,7 @@ Gem::Specification.new do |s|
|
||||||
]
|
]
|
||||||
s.files = [
|
s.files = [
|
||||||
".gitignore",
|
".gitignore",
|
||||||
|
".rspec",
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"MIT-LICENSE",
|
"MIT-LICENSE",
|
||||||
"README.rdoc",
|
"README.rdoc",
|
||||||
|
@ -29,7 +30,6 @@ Gem::Specification.new do |s|
|
||||||
"benchmark/query_without_mysql_casting.rb",
|
"benchmark/query_without_mysql_casting.rb",
|
||||||
"benchmark/sequel.rb",
|
"benchmark/sequel.rb",
|
||||||
"benchmark/setup_db.rb",
|
"benchmark/setup_db.rb",
|
||||||
"benchmark/thread_alone.rb",
|
|
||||||
"examples/eventmachine.rb",
|
"examples/eventmachine.rb",
|
||||||
"examples/threaded.rb",
|
"examples/threaded.rb",
|
||||||
"ext/mysql2/client.c",
|
"ext/mysql2/client.c",
|
||||||
|
@ -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",
|
||||||
|
@ -54,10 +55,11 @@ Gem::Specification.new do |s|
|
||||||
"spec/mysql2/error_spec.rb",
|
"spec/mysql2/error_spec.rb",
|
||||||
"spec/mysql2/result_spec.rb",
|
"spec/mysql2/result_spec.rb",
|
||||||
"spec/rcov.opts",
|
"spec/rcov.opts",
|
||||||
"spec/spec.opts",
|
|
||||||
"spec/spec_helper.rb",
|
"spec/spec_helper.rb",
|
||||||
"tasks/benchmarks.rake",
|
"tasks/benchmarks.rake",
|
||||||
"tasks/compile.rake",
|
"tasks/compile.rake",
|
||||||
|
"tasks/jeweler.rake",
|
||||||
|
"tasks/rspec.rake",
|
||||||
"tasks/vendor_mysql.rake"
|
"tasks/vendor_mysql.rake"
|
||||||
]
|
]
|
||||||
s.homepage = %q{http://github.com/brianmario/mysql2}
|
s.homepage = %q{http://github.com/brianmario/mysql2}
|
||||||
|
|
|
@ -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
|
|
@ -1,26 +1,49 @@
|
||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
require 'spec_helper'
|
if defined? EventMachine
|
||||||
require 'mysql2/em'
|
require 'spec_helper'
|
||||||
|
require 'mysql2/em'
|
||||||
|
|
||||||
describe Mysql2::EM::Client do
|
describe Mysql2::EM::Client do
|
||||||
it "should support async queries" do
|
it "should support async queries" do
|
||||||
results = []
|
results = []
|
||||||
EM.run do
|
EM.run do
|
||||||
client1 = Mysql2::EM::Client.new
|
client1 = Mysql2::EM::Client.new
|
||||||
defer1 = client1.query "SELECT sleep(0.05) as first_query"
|
defer1 = client1.query "SELECT sleep(0.1) as first_query"
|
||||||
defer1.callback do |result|
|
defer1.callback do |result|
|
||||||
results << result.first
|
results << result.first
|
||||||
EM.stop_event_loop
|
EM.stop_event_loop
|
||||||
|
end
|
||||||
|
|
||||||
|
client2 = Mysql2::EM::Client.new
|
||||||
|
defer2 = client2.query "SELECT sleep(0.025) second_query"
|
||||||
|
defer2.callback do |result|
|
||||||
|
results << result.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
client2 = Mysql2::EM::Client.new
|
results[0].keys.should include("second_query")
|
||||||
defer2 = client2.query "SELECT sleep(0.025) second_query"
|
results[1].keys.should include("first_query")
|
||||||
defer2.callback do |result|
|
end
|
||||||
results << result.first
|
|
||||||
end
|
it "should support queries in callbacks" do
|
||||||
|
results = []
|
||||||
|
EM.run do
|
||||||
|
client = Mysql2::EM::Client.new
|
||||||
|
defer1 = client.query "SELECT sleep(0.025) as first_query"
|
||||||
|
defer1.callback do |result|
|
||||||
|
results << result.first
|
||||||
|
defer2 = client.query "SELECT sleep(0.025) as second_query"
|
||||||
|
defer2.callback do |result|
|
||||||
|
results << result.first
|
||||||
|
EM.stop_event_loop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results[0].keys.should include("first_query")
|
||||||
|
results[1].keys.should include("second_query")
|
||||||
end
|
end
|
||||||
|
|
||||||
results[0].keys.should include("second_query")
|
|
||||||
results[1].keys.should include("first_query")
|
|
||||||
end
|
end
|
||||||
end
|
else
|
||||||
|
puts "EventMachine not installed, skipping the specs that use it"
|
||||||
|
end
|
|
@ -23,10 +23,10 @@ describe Mysql2::Client do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
client = klient.new :flags => Mysql2::Client::FOUND_ROWS
|
client = klient.new :flags => Mysql2::Client::FOUND_ROWS
|
||||||
client.connect_args.last.last.should == Mysql2::Client::FOUND_ROWS
|
(client.connect_args.last.last & Mysql2::Client::FOUND_ROWS).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should default flags to 0" do
|
it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
|
||||||
klient = Class.new(Mysql2::Client) do
|
klient = Class.new(Mysql2::Client) do
|
||||||
attr_reader :connect_args
|
attr_reader :connect_args
|
||||||
def connect *args
|
def connect *args
|
||||||
|
@ -35,7 +35,12 @@ describe Mysql2::Client do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
client = klient.new
|
client = klient.new
|
||||||
client.connect_args.last.last.should == 0
|
(client.connect_args.last.last & (Mysql2::Client::REMEMBER_OPTIONS |
|
||||||
|
Mysql2::Client::LONG_PASSWORD |
|
||||||
|
Mysql2::Client::LONG_FLAG |
|
||||||
|
Mysql2::Client::TRANSACTIONS |
|
||||||
|
Mysql2::Client::PROTOCOL_41 |
|
||||||
|
Mysql2::Client::SECURE_CONNECTION)).should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should have a global default_query_options hash" do
|
it "should have a global default_query_options hash" do
|
||||||
|
@ -71,13 +76,28 @@ describe Mysql2::Client do
|
||||||
|
|
||||||
it "should be able to close properly" do
|
it "should be able to close properly" do
|
||||||
@client.close.should be_nil
|
@client.close.should be_nil
|
||||||
|
lambda {
|
||||||
|
@client.query "SELECT 1"
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should respond to #query" do
|
it "should respond to #query" 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))
|
||||||
|
@ -103,6 +123,20 @@ describe Mysql2::Client do
|
||||||
}.should raise_error(Mysql2::Error)
|
}.should raise_error(Mysql2::Error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should require an open connection" do
|
||||||
|
@client.close
|
||||||
|
lambda {
|
||||||
|
@client.query "SELECT 1"
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
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/
|
||||||
|
@ -137,25 +171,34 @@ describe Mysql2::Client do
|
||||||
@client.should respond_to(:escape)
|
@client.should respond_to(:escape)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "#escape should return a new SQL-escape version of the passed string" do
|
context "#escape" do
|
||||||
@client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
|
it "should return a new SQL-escape version of the passed string" do
|
||||||
end
|
@client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
|
||||||
|
end
|
||||||
|
|
||||||
it "#escape should return the passed string if nothing was escaped" do
|
it "should return the passed string if nothing was escaped" do
|
||||||
str = "plain"
|
str = "plain"
|
||||||
@client.escape(str).object_id.should eql(str.object_id)
|
@client.escape(str).object_id.should eql(str.object_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "#escape should not overflow the thread stack" do
|
it "should not overflow the thread stack" do
|
||||||
lambda {
|
lambda {
|
||||||
Thread.new { @client.escape("'" * 256 * 1024) }.join
|
Thread.new { @client.escape("'" * 256 * 1024) }.join
|
||||||
}.should_not raise_error(SystemStackError)
|
}.should_not raise_error(SystemStackError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "#escape should not overflow the process stack" do
|
it "should not overflow the process stack" do
|
||||||
lambda {
|
lambda {
|
||||||
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
|
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
|
||||||
}.should_not raise_error(SystemStackError)
|
}.should_not raise_error(SystemStackError)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should require an open connection" do
|
||||||
|
@client.close
|
||||||
|
lambda {
|
||||||
|
@client.escape ""
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should respond to #info" do
|
it "should respond to #info" do
|
||||||
|
@ -203,6 +246,13 @@ describe Mysql2::Client do
|
||||||
server_info[:version].class.should eql(String)
|
server_info[:version].class.should eql(String)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "#server_info should require an open connection" do
|
||||||
|
@client.close
|
||||||
|
lambda {
|
||||||
|
@client.server_info
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
end
|
||||||
|
|
||||||
if defined? Encoding
|
if defined? Encoding
|
||||||
context "strings returned by #server_info" do
|
context "strings returned by #server_info" do
|
||||||
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
||||||
|
@ -231,6 +281,13 @@ describe Mysql2::Client do
|
||||||
@client.socket.should_not eql(0)
|
@client.socket.should_not eql(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "#socket should require an open connection" do
|
||||||
|
@client.close
|
||||||
|
lambda {
|
||||||
|
@client.socket
|
||||||
|
}.should raise_error(Mysql2::Error)
|
||||||
|
end
|
||||||
|
|
||||||
it "should raise a Mysql2::Error exception upon connection failure" do
|
it "should raise a Mysql2::Error exception upon connection failure" do
|
||||||
lambda {
|
lambda {
|
||||||
bad_client = Mysql2::Client.new :host => "dfjhdi9wrhw", :username => 'asdfasdf8d2h'
|
bad_client = Mysql2::Client.new :host => "dfjhdi9wrhw", :username => 'asdfasdf8d2h'
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
--format specdoc
|
|
||||||
--colour
|
|
|
@ -1,10 +1,11 @@
|
||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
require 'rubygems'
|
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
||||||
|
require 'rspec'
|
||||||
require 'mysql2'
|
require 'mysql2'
|
||||||
require 'timeout'
|
require 'timeout'
|
||||||
|
|
||||||
Spec::Runner.configure do |config|
|
RSpec.configure do |config|
|
||||||
config.before(:all) do
|
config.before(:all) do
|
||||||
client = Mysql2::Client.new :database => 'test'
|
client = Mysql2::Client.new :database => 'test'
|
||||||
client.query %[
|
client.query %[
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
begin
|
||||||
|
require 'jeweler'
|
||||||
|
JEWELER = Jeweler::Tasks.new do |gem|
|
||||||
|
gem.name = "mysql2"
|
||||||
|
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
|
||||||
|
gem.email = "seniorlopez@gmail.com"
|
||||||
|
gem.homepage = "http://github.com/brianmario/mysql2"
|
||||||
|
gem.authors = ["Brian Lopez"]
|
||||||
|
gem.require_paths = ["lib", "ext"]
|
||||||
|
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
|
||||||
|
gem.files = `git ls-files`.split("\n")
|
||||||
|
gem.extensions = ["ext/mysql2/extconf.rb"]
|
||||||
|
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
|
||||||
|
end
|
||||||
|
rescue LoadError
|
||||||
|
puts "jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
begin
|
||||||
|
require 'rspec'
|
||||||
|
require 'rspec/core/rake_task'
|
||||||
|
|
||||||
|
desc "Run all examples with RCov"
|
||||||
|
RSpec::Core::RakeTask.new('spec:rcov') do |t|
|
||||||
|
t.rcov = true
|
||||||
|
end
|
||||||
|
RSpec::Core::RakeTask.new('spec') do |t|
|
||||||
|
t.verbose = true
|
||||||
|
end
|
||||||
|
|
||||||
|
task :default => :spec
|
||||||
|
rescue LoadError
|
||||||
|
puts "rspec, or one of its dependencies, is not available. Install it with: sudo gem install rspec"
|
||||||
|
end
|
Loading…
Reference in New Issue