Compare commits

...

23 Commits
stmt ... master

Author SHA1 Message Date
John Bintz b99e0a057a add LD_RUN_PATH when using hard coded mysql paths 2010-12-07 10:24:30 -05:00
Brian Lopez 52f62c8b44 compiler warnings are annoying 2010-11-27 14:56:05 -08:00
Brian Lopez 66f595a406 Merge branch 'em_fiber' of https://github.com/dj2/mysql2 into dj2-em_fiber 2010-11-27 14:46:34 -08:00
dan sinclair 5f6ff0d4a8 forgot to remove debug 2010-11-27 15:32:54 -05:00
Brian Lopez 80697d11b2 we don't need to print the error here as the caller should be handling that on their own the way they want to 2010-11-27 11:10:18 -08:00
dan sinclair dac2f02c9b if no reactor use synch query 2010-11-26 22:42:34 -05:00
dan sinclair 9d49728c30 add em_fiber spec 2010-11-26 22:42:09 -05:00
dj2 c2e2f0c46c add fibered em connection without activerecord 2010-11-26 11:01:20 -05:00
Youhei Kondou 550c68cade Fix to install with MariDB on Windows 2010-11-13 17:47:58 +09:00
Brian Lopez d48846f13b add support for :read_timeout to be set on a connection 2010-11-09 12:27:04 -08:00
Brian Lopez 99766a2303 mysql_num_fields returns an unsigned int 2010-10-31 12:37:53 -07:00
Brian Lopez badc5e04e3 resultFreed flag only needs to be one byte 2010-10-31 12:34:18 -07:00
Brian Lopez 974a5658d6 active and closed flags only need to be one byte 2010-10-31 12:31:54 -07:00
Brian Lopez 60b8d061ac mysql_errno returns an unsigned int 2010-10-31 12:24:27 -07:00
Brian Lopez 2b37ace3dc only set binary ruby encoding on fields that have a binary flag *and* encoding set 2010-10-31 12:11:20 -07:00
Brian Lopez 1057f976d0 ensure the query is a string earlier in the Mysql2::Client#query codepath for 1.9 2010-10-31 10:11:59 -07:00
Brian Lopez 90ddb63e52 use our own index def class for better compatibility across ActiveRecord versions 2010-10-27 15:36:25 -07:00
Brian Lopez 426cff8adc bump to 0.2.6 to push fixed win32 gems 2010-10-19 17:24:55 -07:00
Brian Lopez f79bf6261e Version bump to 0.2.6 2010-10-19 17:23:43 -07:00
Brian Lopez 05df9e312d update files for 0.2.5 release 2010-10-19 16:33:07 -07:00
Brian Lopez 60fd02ebe6 Version bump to 0.2.5 2010-10-19 16:32:42 -07:00
Brian Lopez 7e75f5ed4c make sure we always set wait_timeout even if a bad value was given 2010-10-19 08:21:41 -07:00
Anko painting e7dcf37bd4 fix to CFLAGS to allow compilation on SPARC with sunstudio compiler 2010-10-18 18:33:34 -07:00
17 changed files with 148 additions and 21 deletions

View File

@ -1,5 +1,17 @@
# 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)
* 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

View File

@ -1 +1 @@
0.2.4
0.2.6

View File

@ -76,7 +76,7 @@ static void rb_mysql_client_mark(void * wrapper) {
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)));
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_exc_raise(e);
return Qnil;
@ -264,7 +264,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
fd_set fdset;
int fd, retval;
int async = 0;
VALUE opts, defaults;
VALUE opts, defaults, read_timeout;
GET_CLIENT(self);
REQUIRE_OPEN_DB(wrapper);
@ -290,6 +290,7 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
opts = defaults;
}
Check_Type(args.sql, T_STRING);
#ifdef HAVE_RUBY_ENCODING_H
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
// 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);
}
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) {
// the below code is largely from do_mysql
// 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_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) {
rb_sys_fail(0);

View File

@ -33,8 +33,8 @@ void init_mysql2_client();
typedef struct {
VALUE encoding;
short int active;
short int closed;
char active;
char closed;
MYSQL *client;
} mysql_client_wrapper;

View File

@ -57,9 +57,13 @@ end
asplode h unless have_header h
end
unless RUBY_PLATFORM =~ /mswin/
unless RUBY_PLATFORM =~ /mswin/ or RUBY_PLATFORM =~ /sparc/
$CFLAGS << ' -Wall -funroll-loops'
end
# $CFLAGS << ' -O0 -ggdb3 -Wextra'
if hard_mysql_path = $libs[%r{-L(/[^ ]+)}, 1]
$LDFLAGS << " -Wl,-rpath,#{hard_mysql_path}"
end
create_makefile('mysql2/mysql2')

View File

@ -4,6 +4,12 @@
#include <ruby.h>
#include <fcntl.h>
#ifndef HAVE_UINT
#define HAVE_UINT
typedef unsigned short ushort;
typedef unsigned int uint;
#endif
#ifdef HAVE_MYSQL_H
#include <mysql.h>
#include <mysql_com.h>

View File

@ -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]);
#ifdef HAVE_RUBY_ENCODING_H
// 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);
} else {
// lookup the encoding configured on this field

View File

@ -8,10 +8,10 @@ typedef struct {
VALUE fields;
VALUE rows;
VALUE encoding;
long numberOfFields;
unsigned int numberOfFields;
unsigned long numberOfRows;
unsigned long lastRowProcessed;
short int resultFreed;
char resultFreed;
MYSQL_RES *result;
} mysql2_result_wrapper;

View File

@ -35,7 +35,6 @@ module Mysql2
results = @client.async_result
@deferable.succeed(results)
rescue Exception => e
puts e.backtrace.join("\n\t")
@deferable.fail(e)
end
end

View File

@ -18,6 +18,9 @@ module ActiveRecord
end
module ConnectionAdapters
class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc:
end
class Mysql2Column < Column
BOOL = "tinyint(1)"
def extract_default(default)
@ -447,7 +450,7 @@ module ActiveRecord
if current_index != row[:Key_name]
next if row[:Key_name] == PRIMARY # skip the primary key
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
indexes.last.columns << row[:Column_name]
@ -622,8 +625,9 @@ module ActiveRecord
variable_assignments << "NAMES '#{encoding}'" if encoding
# increase timeout so mysql server doesn't disconnect us
wait_timeout = @config[:wait_timeout] || 2592000
variable_assignments << "@@wait_timeout = #{wait_timeout}" if wait_timeout.is_a?(Fixnum)
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)
end

View File

@ -12,5 +12,5 @@ require 'mysql2/result'
#
# A modern, simple and very fast Mysql library for Ruby - binding to libmysql
module Mysql2
VERSION = "0.2.4"
VERSION = "0.2.6"
end

View File

@ -24,6 +24,11 @@ module Mysql2
# force the encoding to 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))
user = opts[:username]

View File

@ -23,10 +23,14 @@ module Mysql2
end
def query(sql, opts={})
super(sql, opts.merge(:async => true))
deferable = ::EM::DefaultDeferrable.new
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
deferable
if ::EM.reactor_running?
super(sql, opts.merge(:async => true))
deferable = ::EM::DefaultDeferrable.new
::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
deferable
else
super(sql, opts)
end
end
end
end

29
lib/mysql2/em_fiber.rb Normal file
View File

@ -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

View File

@ -5,11 +5,11 @@
Gem::Specification.new do |s|
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.authors = ["Brian Lopez"]
s.date = %q{2010-10-18}
s.date = %q{2010-10-19}
s.email = %q{seniorlopez@gmail.com}
s.extensions = ["ext/mysql2/extconf.rb"]
s.extra_rdoc_files = [
@ -46,6 +46,7 @@ Gem::Specification.new do |s|
"lib/mysql2.rb",
"lib/mysql2/client.rb",
"lib/mysql2/em.rb",
"lib/mysql2/em_fiber.rb",
"lib/mysql2/error.rb",
"lib/mysql2/result.rb",
"mysql2.gemspec",

22
spec/em/em_fiber_spec.rb Normal file
View File

@ -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

View File

@ -85,7 +85,19 @@ describe Mysql2::Client do
@client.should respond_to(:query)
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
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
@client.query "SELECT 1", :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)
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)
# and may fail on a loaded system
if RUBY_PLATFORM !~ /mingw|mswin/