From 14accdf8d1bf557f652c19b870316094a7441334 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 27 Mar 2012 17:10:01 -0700 Subject: [PATCH 01/40] backporting table_exists? from Rails 3.1.x. Fixes #235 --- .../connection_adapters/mysql2_adapter.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 442ba6a3c..87f6ccf60 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -386,6 +386,20 @@ def tables(name = nil) tables end + def table_exists?(name) + return true if super + + name = name.to_s + schema, table = name.split('.', 2) + + unless table # A table was provided without a schema + table = schema + schema = nil + end + + tables(nil, schema).include? table + end + def drop_table(table_name, options = {}) super(table_name, options) end From 1ab2f4bca30083fbaad7f4a6fe745f580cc06cae Mon Sep 17 00:00:00 2001 From: Jonathan Nevelson Date: Mon, 4 Jun 2012 17:32:43 -0700 Subject: [PATCH 02/40] Fix case where :limit is nil --- lib/active_record/connection_adapters/mysql2_adapter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 87f6ccf60..1a4c87653 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -314,13 +314,13 @@ def release_savepoint end def add_limit_offset!(sql, options) - limit, offset = options[:limit], options[:offset] + limit, offset = options.fetch(:limit, 99999999999), options[:offset] if limit && offset sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" elsif limit sql << " LIMIT #{sanitize_limit(limit)}" elsif offset - sql << " OFFSET #{offset.to_i}" + sql << " LIMIT #{sanitize_limit(limit)} OFFSET #{offset.to_i}" end sql end From 3105855abf5dbdf2fceef8c10c304fd5484229af Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 4 Aug 2012 06:52:56 +0100 Subject: [PATCH 03/40] Backport of fix from rails/rails#5173 Rather than use the MySQL specific TINYTEXT, MEDIUMTEXT and LONGTEXT datatypes, Active Record migrations use TEXT(n) where n is the limit specified by the developer. Unfortunately how MySQL interprets n depends on the column's encoding so any limit above 5592405 will be interpreted as a LONGTEXT. This commit fixes this by interpreting the limit within the adapter and using the specific MySQL datatype as appropriate. --- .../connection_adapters/mysql2_adapter.rb | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 87f6ccf60..7ba5768c0 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -494,15 +494,26 @@ def rename_column(table_name, column_name, new_column_name) # Maps logical Rails types to MySQL-specific data types. def type_to_sql(type, limit = nil, precision = nil, scale = nil) - return super unless type.to_s == 'integer' - - case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when nil, 4, 11; 'int(11)' # compatibility with MySQL default - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}") + case type.to_s + when 'integer' + case limit + when 1; 'tinyint' + when 2; 'smallint' + when 3; 'mediumint' + when nil, 4, 11; 'int(11)' # compatibility with MySQL default + when 5..8; 'bigint' + else raise(ActiveRecordError, "No integer type has byte size #{limit}") + end + when 'text' + case limit + when 0..0xff; 'tinytext' + when nil, 0x100..0xffff; 'text' + when 0x10000..0xffffff; 'mediumtext' + when 0x1000000..0xffffffff; 'longtext' + else raise(ActiveRecordError, "No text type has character length #{limit}") + end + else + super end end From 8f528e2e12dbb573eac9eed65f36c2b0ec193aa0 Mon Sep 17 00:00:00 2001 From: Andrew White Date: Sat, 4 Aug 2012 07:36:13 +0100 Subject: [PATCH 04/40] Fix backport of table_exists? in 14accdf8d1 The backport of table_exists? expects tables to accept an arity of 2, whereas the version in the Mysql2Adapter only has an arity of 1. The second parameter provides for querying tables in databases other than the currently selected database. This commit fixes this by backporting the tables method from the MysqlAdapter in Rails 3.0.x. --- lib/active_record/connection_adapters/mysql2_adapter.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 7ba5768c0..55a2aa73f 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -378,9 +378,13 @@ def collation show_variable 'collation_database' end - def tables(name = nil) + def tables(name = nil, database = nil) tables = [] - execute("SHOW TABLES", name).each do |field| + + sql = "SHOW TABLES " + sql << "IN #{quote_table_name(database)} " if database + + execute(sql, 'SCHEMA').each do |field| tables << field.first end tables From 653eea5d1aa6152962c4b88e562a8111a51ba767 Mon Sep 17 00:00:00 2001 From: Jonathan Nevelson Date: Wed, 8 Aug 2012 13:53:24 -0700 Subject: [PATCH 05/40] Change limit value to Arel default --- lib/active_record/connection_adapters/mysql2_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 1a4c87653..c61ff6de5 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -314,7 +314,7 @@ def release_savepoint end def add_limit_offset!(sql, options) - limit, offset = options.fetch(:limit, 99999999999), options[:offset] + limit, offset = options.fetch(:limit, 18446744073709551615), options[:offset] if limit && offset sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" elsif limit From efc161952f06fed94495558dc335778555020304 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 8 Aug 2012 14:59:08 -0700 Subject: [PATCH 06/40] fix some tests from the testing config patch --- spec/em/em_fiber_spec.rb | 2 +- spec/em/em_spec.rb | 10 +++++----- spec/mysql2/client_spec.rb | 20 ++++++++------------ spec/mysql2/error_spec.rb | 4 ++-- spec/mysql2/result_spec.rb | 6 +++--- tasks/rspec.rake | 8 +++++--- 6 files changed, 24 insertions(+), 26 deletions(-) diff --git a/spec/em/em_fiber_spec.rb b/spec/em/em_fiber_spec.rb index 16a162d09..4d51e9958 100644 --- a/spec/em/em_fiber_spec.rb +++ b/spec/em/em_fiber_spec.rb @@ -8,7 +8,7 @@ results = [] EM.run do Fiber.new { - client1 = Mysql2::EM::Fiber::Client.new + client1 = Mysql2::EM::Fiber::Client.new DatabaseCredentials['root'] results = client1.query "SELECT sleep(0.1) as first_query" EM.stop_event_loop }.resume diff --git a/spec/em/em_spec.rb b/spec/em/em_spec.rb index c9a504a17..5a6b42ee2 100644 --- a/spec/em/em_spec.rb +++ b/spec/em/em_spec.rb @@ -8,14 +8,14 @@ it "should support async queries" do results = [] EM.run do - client1 = Mysql2::EM::Client.new + client1 = Mysql2::EM::Client.new DatabaseCredentials['root'] defer1 = client1.query "SELECT sleep(0.1) as first_query" defer1.callback do |result| results << result.first EM.stop_event_loop end - client2 = Mysql2::EM::Client.new + client2 = Mysql2::EM::Client.new DatabaseCredentials['root'] defer2 = client2.query "SELECT sleep(0.025) second_query" defer2.callback do |result| results << result.first @@ -29,7 +29,7 @@ it "should support queries in callbacks" do results = [] EM.run do - client = Mysql2::EM::Client.new + client = Mysql2::EM::Client.new DatabaseCredentials['root'] defer1 = client.query "SELECT sleep(0.025) as first_query" defer1.callback do |result| results << result.first @@ -48,7 +48,7 @@ it "should not swallow exceptions raised in callbacks" do lambda { EM.run do - client = Mysql2::EM::Client.new + client = Mysql2::EM::Client.new DatabaseCredentials['root'] defer = client.query "SELECT sleep(0.1) as first_query" defer.callback do |result| raise 'some error' @@ -63,7 +63,7 @@ end context 'when an exception is raised by the client' do - let(:client) { Mysql2::EM::Client.new } + let(:client) { Mysql2::EM::Client.new DatabaseCredentials['root'] } let(:error) { StandardError.new('some error') } before { client.stub(:async_result).and_raise(error) } diff --git a/spec/mysql2/client_spec.rb b/spec/mysql2/client_spec.rb index dc3b84cb5..e4f734afd 100644 --- a/spec/mysql2/client_spec.rb +++ b/spec/mysql2/client_spec.rb @@ -3,7 +3,7 @@ describe Mysql2::Client do before(:each) do - @client = Mysql2::Client.new + @client = Mysql2::Client.new DatabaseCredentials['root'] end if defined? Encoding @@ -161,7 +161,7 @@ def connect *args end it "should timeout if we wait longer than :read_timeout" do - client = Mysql2::Client.new(:read_timeout => 1) + client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:read_timeout => 1)) lambda { client.query("SELECT sleep(2)") }.should raise_error(Mysql2::Error) @@ -220,7 +220,7 @@ def connect *args end it "should handle Timeouts without leaving the connection hanging if reconnect is true" do - client = Mysql2::Client.new(:reconnect => true) + client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:reconnect => true)) begin Timeout.timeout(1) do client.query("SELECT sleep(2)") @@ -236,11 +236,7 @@ def connect *args it "threaded queries should be supported" do threads, results = [], {} connect = lambda{ - Mysql2::Client.new( - :host => DatabaseCredentials['root']['host'], - :username => DatabaseCredentials["root"]["username"], - :password => DatabaseCredentials["root"]["password"] - ) + Mysql2::Client.new(DatabaseCredentials['root']) } Timeout.timeout(0.7) do 5.times { @@ -285,7 +281,7 @@ def connect *args context "Multiple results sets" do before(:each) do - @multi_client = Mysql2::Client.new( :flags => Mysql2::Client::MULTI_STATEMENTS) + @multi_client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:flags => Mysql2::Client::MULTI_STATEMENTS)) end it "returns multiple result sets" do @@ -412,7 +408,7 @@ def connect *args Encoding.default_internal = nil @client.info[:version].encoding.should eql(Encoding.find('utf-8')) - client2 = Mysql2::Client.new :encoding => 'ascii' + client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii')) client2.info[:version].encoding.should eql(Encoding.find('us-ascii')) end @@ -451,7 +447,7 @@ def connect *args Encoding.default_internal = nil @client.server_info[:version].encoding.should eql(Encoding.find('utf-8')) - client2 = Mysql2::Client.new :encoding => 'ascii' + client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii')) client2.server_info[:version].encoding.should eql(Encoding.find('us-ascii')) end @@ -470,7 +466,7 @@ def connect *args }.should raise_error(Mysql2::Error) lambda { - good_client = Mysql2::Client.new + good_client = Mysql2::Client.new DatabaseCredentials['root'] }.should_not raise_error(Mysql2::Error) end diff --git a/spec/mysql2/error_spec.rb b/spec/mysql2/error_spec.rb index 882a5f87f..315af4017 100644 --- a/spec/mysql2/error_spec.rb +++ b/spec/mysql2/error_spec.rb @@ -3,14 +3,14 @@ describe Mysql2::Error do before(:each) do - @client = Mysql2::Client.new :encoding => "utf8" + @client = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8")) begin @client.query("HAHAHA") rescue Mysql2::Error => e @error = e end - @client2 = Mysql2::Client.new :encoding => "big5" + @client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5")) begin @client2.query("HAHAHA") rescue Mysql2::Error => e diff --git a/spec/mysql2/result_spec.rb b/spec/mysql2/result_spec.rb index 2d7a89068..764162e59 100644 --- a/spec/mysql2/result_spec.rb +++ b/spec/mysql2/result_spec.rb @@ -307,7 +307,7 @@ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result['enum_test'].encoding.should eql(Encoding.find('utf-8')) - client2 = Mysql2::Client.new :encoding => 'ascii' + client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii')) client2.query "USE test" result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result['enum_test'].encoding.should eql(Encoding.find('us-ascii')) @@ -336,7 +336,7 @@ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result['set_test'].encoding.should eql(Encoding.find('utf-8')) - client2 = Mysql2::Client.new :encoding => 'ascii' + client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii')) client2.query "USE test" result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result['set_test'].encoding.should eql(Encoding.find('us-ascii')) @@ -418,7 +418,7 @@ result = @client.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result[field].encoding.should eql(Encoding.find('utf-8')) - client2 = Mysql2::Client.new :encoding => 'ascii' + client2 = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => 'ascii')) client2.query "USE test" result = client2.query("SELECT * FROM mysql2_test ORDER BY id DESC LIMIT 1").first result[field].encoding.should eql(Encoding.find('us-ascii')) diff --git a/tasks/rspec.rake b/tasks/rspec.rake index 714f20604..c4173f6e8 100644 --- a/tasks/rspec.rake +++ b/tasks/rspec.rake @@ -17,8 +17,10 @@ end file 'spec/configuration.yml' => 'spec/configuration.yml.example' do |task| CLEAN.exclude task.name - cp task.prerequisites.first, task.name - sh "sed -i 's/LOCALUSERNAME/#{ENV['USER']}/' #{task.name}" + src_path = File.expand_path("../../#{task.prerequisites.first}", __FILE__) + dst_path = File.expand_path("../../#{task.name}", __FILE__) + cp src_path, dst_path + sh "sed -i 's/LOCALUSERNAME/#{ENV['USER']}/' #{dst_path}" end -task :spec => :'spec/configuration.yml' +Rake::Task[:spec].prerequisites << :'spec/configuration.yml' From f53c3e1d97d32f0d9fcc66d20ad5ec94b3c0bb4a Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 8 Aug 2012 15:15:40 -0700 Subject: [PATCH 07/40] 1.9.3 is preferred with rbenv too --- .rbenv-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .rbenv-version diff --git a/.rbenv-version b/.rbenv-version new file mode 100644 index 000000000..77fee73a8 --- /dev/null +++ b/.rbenv-version @@ -0,0 +1 @@ +1.9.3 From e9d90a3addf024fe3f0e25a6a071196a84b3c1d5 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 8 Aug 2012 15:22:35 -0700 Subject: [PATCH 08/40] bump version for 0.2.19 beta 1 release --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4232260d9..42d237eaa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.18) + mysql2 (0.2.19b1) GEM remote: http://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index c96c85dbc..21f0dad7e 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.18" + VERSION = "0.2.19b1" end From d9431c5cb693f049f7762d71bfa7a926779df5b1 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 9 Aug 2012 07:25:29 -0700 Subject: [PATCH 09/40] Mysql2::Client#more_results should be a predicate --- ext/mysql2/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 69641571b..547c1980d 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1021,7 +1021,7 @@ void init_mysql2_client() { rb_define_method(cMysql2Client, "thread_id", rb_mysql_client_thread_id, 0); rb_define_method(cMysql2Client, "ping", rb_mysql_client_ping, 0); rb_define_method(cMysql2Client, "select_db", rb_mysql_client_select_db, 1); - rb_define_method(cMysql2Client, "more_results", rb_mysql_client_more_results, 0); + rb_define_method(cMysql2Client, "more_results?", rb_mysql_client_more_results, 0); rb_define_method(cMysql2Client, "next_result", rb_mysql_client_next_result, 0); rb_define_method(cMysql2Client, "store_result", rb_mysql_client_store_result, 0); rb_define_method(cMysql2Client, "options", rb_mysql_client_options, 2); From aa1723040974b83592291b53d01f03d2b7e256f6 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 9 Aug 2012 07:25:38 -0700 Subject: [PATCH 10/40] whitespace --- ext/mysql2/client.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 547c1980d..c8d0cb57f 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -801,7 +801,7 @@ static VALUE rb_mysql_client_select_db(VALUE self, VALUE db) args.db = StringValuePtr(db); if (rb_thread_blocking_region(nogvl_select_db, &args, RUBY_UBF_IO, 0) == Qfalse) - rb_raise_mysql2_error(wrapper); + rb_raise_mysql2_error(wrapper); return db; } @@ -858,14 +858,14 @@ static VALUE rb_mysql_client_store_result(VALUE self) #ifdef HAVE_RUBY_ENCODING_H mysql2_result_wrapper * result_wrapper; #endif - - + + GET_CLIENT(self); // MYSQL_RES* res = mysql_store_result(wrapper->client); // if (res == NULL) // mysql_raise(wrapper->client); // return mysqlres2obj(res); - + result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, wrapper, RUBY_UBF_IO, 0); if (result == NULL) { @@ -885,7 +885,7 @@ static VALUE rb_mysql_client_store_result(VALUE self) result_wrapper->encoding = wrapper->encoding; #endif return resultObj; - + } #ifdef HAVE_RUBY_ENCODING_H From a8aa5d39f87818cc7154198e8d39d0cb746b1dad Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Fri, 10 Aug 2012 15:31:32 -0700 Subject: [PATCH 11/40] bump version for 0.2.19b2 --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 42d237eaa..2d1ad9876 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19b1) + mysql2 (0.2.19b2) GEM remote: http://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 21f0dad7e..cea040de3 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19b1" + VERSION = "0.2.19b2" end From 3bc61603d1052c3f3305ed7465cc48020a29e797 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 10:57:57 -0700 Subject: [PATCH 12/40] fix overflow in flags --- ext/mysql2/client.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index c8d0cb57f..34ab5a08b 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1054,107 +1054,107 @@ void init_mysql2_client() { #ifdef CLIENT_LONG_PASSWORD rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), - INT2NUM(CLIENT_LONG_PASSWORD)); + LONG2NUM(CLIENT_LONG_PASSWORD)); #endif #ifdef CLIENT_FOUND_ROWS rb_const_set(cMysql2Client, rb_intern("FOUND_ROWS"), - INT2NUM(CLIENT_FOUND_ROWS)); + LONG2NUM(CLIENT_FOUND_ROWS)); #endif #ifdef CLIENT_LONG_FLAG rb_const_set(cMysql2Client, rb_intern("LONG_FLAG"), - INT2NUM(CLIENT_LONG_FLAG)); + LONG2NUM(CLIENT_LONG_FLAG)); #endif #ifdef CLIENT_CONNECT_WITH_DB rb_const_set(cMysql2Client, rb_intern("CONNECT_WITH_DB"), - INT2NUM(CLIENT_CONNECT_WITH_DB)); + LONG2NUM(CLIENT_CONNECT_WITH_DB)); #endif #ifdef CLIENT_NO_SCHEMA rb_const_set(cMysql2Client, rb_intern("NO_SCHEMA"), - INT2NUM(CLIENT_NO_SCHEMA)); + LONG2NUM(CLIENT_NO_SCHEMA)); #endif #ifdef CLIENT_COMPRESS - rb_const_set(cMysql2Client, rb_intern("COMPRESS"), INT2NUM(CLIENT_COMPRESS)); + rb_const_set(cMysql2Client, rb_intern("COMPRESS"), LONG2NUM(CLIENT_COMPRESS)); #endif #ifdef CLIENT_ODBC - rb_const_set(cMysql2Client, rb_intern("ODBC"), INT2NUM(CLIENT_ODBC)); + rb_const_set(cMysql2Client, rb_intern("ODBC"), LONG2NUM(CLIENT_ODBC)); #endif #ifdef CLIENT_LOCAL_FILES rb_const_set(cMysql2Client, rb_intern("LOCAL_FILES"), - INT2NUM(CLIENT_LOCAL_FILES)); + LONG2NUM(CLIENT_LOCAL_FILES)); #endif #ifdef CLIENT_IGNORE_SPACE rb_const_set(cMysql2Client, rb_intern("IGNORE_SPACE"), - INT2NUM(CLIENT_IGNORE_SPACE)); + LONG2NUM(CLIENT_IGNORE_SPACE)); #endif #ifdef CLIENT_PROTOCOL_41 rb_const_set(cMysql2Client, rb_intern("PROTOCOL_41"), - INT2NUM(CLIENT_PROTOCOL_41)); + LONG2NUM(CLIENT_PROTOCOL_41)); #endif #ifdef CLIENT_INTERACTIVE rb_const_set(cMysql2Client, rb_intern("INTERACTIVE"), - INT2NUM(CLIENT_INTERACTIVE)); + LONG2NUM(CLIENT_INTERACTIVE)); #endif #ifdef CLIENT_SSL - rb_const_set(cMysql2Client, rb_intern("SSL"), INT2NUM(CLIENT_SSL)); + rb_const_set(cMysql2Client, rb_intern("SSL"), LONG2NUM(CLIENT_SSL)); #endif #ifdef CLIENT_IGNORE_SIGPIPE rb_const_set(cMysql2Client, rb_intern("IGNORE_SIGPIPE"), - INT2NUM(CLIENT_IGNORE_SIGPIPE)); + LONG2NUM(CLIENT_IGNORE_SIGPIPE)); #endif #ifdef CLIENT_TRANSACTIONS rb_const_set(cMysql2Client, rb_intern("TRANSACTIONS"), - INT2NUM(CLIENT_TRANSACTIONS)); + LONG2NUM(CLIENT_TRANSACTIONS)); #endif #ifdef CLIENT_RESERVED - rb_const_set(cMysql2Client, rb_intern("RESERVED"), INT2NUM(CLIENT_RESERVED)); + rb_const_set(cMysql2Client, rb_intern("RESERVED"), LONG2NUM(CLIENT_RESERVED)); #endif #ifdef CLIENT_SECURE_CONNECTION rb_const_set(cMysql2Client, rb_intern("SECURE_CONNECTION"), - INT2NUM(CLIENT_SECURE_CONNECTION)); + LONG2NUM(CLIENT_SECURE_CONNECTION)); #endif #ifdef CLIENT_MULTI_STATEMENTS rb_const_set(cMysql2Client, rb_intern("MULTI_STATEMENTS"), - INT2NUM(CLIENT_MULTI_STATEMENTS)); + LONG2NUM(CLIENT_MULTI_STATEMENTS)); #endif #ifdef CLIENT_PS_MULTI_RESULTS rb_const_set(cMysql2Client, rb_intern("PS_MULTI_RESULTS"), - INT2NUM(CLIENT_PS_MULTI_RESULTS)); + LONG2NUM(CLIENT_PS_MULTI_RESULTS)); #endif #ifdef CLIENT_SSL_VERIFY_SERVER_CERT rb_const_set(cMysql2Client, rb_intern("SSL_VERIFY_SERVER_CERT"), - INT2NUM(CLIENT_SSL_VERIFY_SERVER_CERT)); + LONG2NUM(CLIENT_SSL_VERIFY_SERVER_CERT)); #endif #ifdef CLIENT_REMEMBER_OPTIONS rb_const_set(cMysql2Client, rb_intern("REMEMBER_OPTIONS"), - INT2NUM(CLIENT_REMEMBER_OPTIONS)); + LONG2NUM(CLIENT_REMEMBER_OPTIONS)); #endif #ifdef CLIENT_ALL_FLAGS rb_const_set(cMysql2Client, rb_intern("ALL_FLAGS"), - INT2NUM(CLIENT_ALL_FLAGS)); + LONG2NUM(CLIENT_ALL_FLAGS)); #endif #ifdef CLIENT_BASIC_FLAGS rb_const_set(cMysql2Client, rb_intern("BASIC_FLAGS"), - INT2NUM(CLIENT_BASIC_FLAGS)); + LONG2NUM(CLIENT_BASIC_FLAGS)); #endif } From 7412b48e3509167fca6239b181aa94ac425c9f9a Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 10:59:40 -0700 Subject: [PATCH 13/40] bump version for 0.2.19b3 release --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2d1ad9876..c1bbcb3e5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19b2) + mysql2 (0.2.19b3) GEM remote: http://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index cea040de3..1a08f77d1 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19b2" + VERSION = "0.2.19b3" end From 7741ee1aac883c8a32b12ae0db4bf19acdf086db Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 11:36:17 -0700 Subject: [PATCH 14/40] allow setting of write_timeout --- ext/mysql2/client.c | 16 ++++++++++++++++ lib/mysql2/client.rb | 2 +- spec/mysql2/client_spec.rb | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 34ab5a08b..18bdd5bbc 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -618,6 +618,11 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) { retval = &intval; break; + case MYSQL_OPT_WRITE_TIMEOUT: + intval = NUM2INT(value); + retval = &intval; + break; + case MYSQL_OPT_LOCAL_INFILE: intval = (value == Qfalse ? 0 : 1); retval = &intval; @@ -926,6 +931,16 @@ static VALUE set_read_timeout(VALUE self, VALUE value) { return _mysql_client_options(self, MYSQL_OPT_READ_TIMEOUT, value); } +static VALUE set_write_timeout(VALUE self, VALUE value) { + long int sec; + Check_Type(value, T_FIXNUM); + sec = FIX2INT(value); + if (sec < 0) { + rb_raise(cMysql2Error, "write_timeout must be a positive integer, you passed %ld", sec); + } + return _mysql_client_options(self, MYSQL_OPT_WRITE_TIMEOUT, value); +} + static VALUE set_charset_name(VALUE self, VALUE value) { char * charset_name; #ifdef HAVE_RUBY_ENCODING_H @@ -1032,6 +1047,7 @@ void init_mysql2_client() { 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, "read_timeout=", set_read_timeout, 1); + rb_define_private_method(cMysql2Client, "write_timeout=", set_write_timeout, 1); rb_define_private_method(cMysql2Client, "local_infile=", set_local_infile, 1); rb_define_private_method(cMysql2Client, "charset_name=", set_charset_name, 1); rb_define_private_method(cMysql2Client, "ssl_set", set_ssl_options, 5); diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index bf89bd2bd..e8c3188d5 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -21,7 +21,7 @@ def initialize(opts = {}) initialize_ext # Set MySQL connection options (each one is a call to mysql_options()) - [:reconnect, :connect_timeout, :local_infile, :read_timeout].each do |key| + [:reconnect, :connect_timeout, :local_infile, :read_timeout, :write_timeout].each do |key| next unless opts.key?(key) send(:"#{key}=", opts[key]) end diff --git a/spec/mysql2/client_spec.rb b/spec/mysql2/client_spec.rb index e4f734afd..51aefc842 100644 --- a/spec/mysql2/client_spec.rb +++ b/spec/mysql2/client_spec.rb @@ -91,6 +91,12 @@ def connect *args }.should raise_error(Mysql2::Error) end + it "should expect write_timeout to be a positive integer" do + lambda { + Mysql2::Client.new(:write_timeout => -1) + }.should raise_error(Mysql2::Error) + end + context "#query" do it "should let you query again if iterating is finished when streaming" do @client.query("SELECT 1 UNION SELECT 2", :stream => true, :cache_rows => false).each {} From 2c80cffb365c40354e15da977558ba194bdf644f Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 11:36:28 -0700 Subject: [PATCH 15/40] ensure connect_timeout is a positive integer --- ext/mysql2/client.c | 6 ++++++ spec/mysql2/client_spec.rb | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 18bdd5bbc..1918e4af1 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -914,6 +914,12 @@ static VALUE set_local_infile(VALUE self, VALUE value) { } static VALUE set_connect_timeout(VALUE self, VALUE value) { + long int sec; + Check_Type(value, T_FIXNUM); + sec = FIX2INT(value); + if (sec < 0) { + rb_raise(cMysql2Error, "connect_timeout must be a positive integer, you passed %ld", sec); + } return _mysql_client_options(self, MYSQL_OPT_CONNECT_TIMEOUT, value); } diff --git a/spec/mysql2/client_spec.rb b/spec/mysql2/client_spec.rb index 51aefc842..949667103 100644 --- a/spec/mysql2/client_spec.rb +++ b/spec/mysql2/client_spec.rb @@ -85,6 +85,12 @@ def connect *args @client.should respond_to(:query) end + it "should expect connect_timeout to be a positive integer" do + lambda { + Mysql2::Client.new(:connect_timeout => -1) + }.should raise_error(Mysql2::Error) + end + it "should expect read_timeout to be a positive integer" do lambda { Mysql2::Client.new(:read_timeout => -1) From 5f40693e0f7f483997cef3c6671adcd0aa9e0a1a Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 11:36:33 -0700 Subject: [PATCH 16/40] whitespace --- lib/mysql2/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mysql2/client.rb b/lib/mysql2/client.rb index e8c3188d5..272e7f5b3 100644 --- a/lib/mysql2/client.rb +++ b/lib/mysql2/client.rb @@ -30,7 +30,7 @@ def initialize(opts = {}) self.charset_name = opts[:encoding] || 'utf8' ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)) - + if [:user,:pass,:hostname,:dbname,:db,:sock].any?{|k| @query_options.has_key?(k) } warn "============= WARNING FROM mysql2 =============" warn "The options :user, :pass, :hostname, :dbname, :db, and :sock will be deprecated at some point in the future." From 7dc9a48c39c1abc6fb51640e29a524da29953193 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 22 Aug 2012 11:38:50 -0700 Subject: [PATCH 17/40] bump version for 0.2.19b4 release --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c1bbcb3e5..2c9ed0918 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19b3) + mysql2 (0.2.19b4) GEM remote: http://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 1a08f77d1..2e97b851a 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19b3" + VERSION = "0.2.19b4" end From 712400a3bfdd91019fa821de072e4bb6ac3f8441 Mon Sep 17 00:00:00 2001 From: Dylan Smith Date: Thu, 7 Feb 2013 05:06:32 -0500 Subject: [PATCH 18/40] active_record: Delegate BigDecimal quoting to abstract adapter. The abstract connection adapter already supports BigDecimal, and removing this code from the mysql2 adapter allows proper quoting when comparing with a string column. --- lib/active_record/connection_adapters/mysql2_adapter.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 027c25980..08eb02a37 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -149,8 +149,6 @@ def quote(value, column = nil) if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) s = column.class.string_to_binary(value).unpack("H*")[0] "x'#{s}'" - elsif value.kind_of?(BigDecimal) - value.to_s("F") else super end From 962733125978cd798403e3e633c9678b678bb925 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Tue, 19 Feb 2013 23:01:09 -0800 Subject: [PATCH 19/40] use local db config if avail --- spec/mysql2/client_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/mysql2/client_spec.rb b/spec/mysql2/client_spec.rb index e7a3618a0..afdec3308 100644 --- a/spec/mysql2/client_spec.rb +++ b/spec/mysql2/client_spec.rb @@ -17,17 +17,17 @@ if defined? Encoding it "should raise an exception on create for invalid encodings" do lambda { - c = Mysql2::Client.new(:encoding => "fake") + c = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "fake")) }.should raise_error(Mysql2::Error) end it "should not raise an exception on create for a valid encoding" do lambda { - c = Mysql2::Client.new(:encoding => "utf8") + c = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "utf8")) }.should_not raise_error(Mysql2::Error) lambda { - c = Mysql2::Client.new(:encoding => "big5") + c = Mysql2::Client.new(DatabaseCredentials['root'].merge(:encoding => "big5")) }.should_not raise_error(Mysql2::Error) end end @@ -416,10 +416,10 @@ def connect *args it "#more_results? should work" do @multi_client.query( "select 1 as 'set_1'; select 2 as 'set_2'") @multi_client.more_results?.should == true - + @multi_client.next_result @multi_client.store_result - + @multi_client.more_results?.should == false end end From 857c6a2393bfcdc9e5693e84894c078b29cae9d8 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 21 Feb 2013 12:48:00 -0600 Subject: [PATCH 20/40] only use default limit value if offset is used without limit --- lib/active_record/connection_adapters/mysql2_adapter.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index 08eb02a37..dc0172781 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -312,12 +312,13 @@ def release_savepoint end def add_limit_offset!(sql, options) - limit, offset = options.fetch(:limit, 18446744073709551615), options[:offset] + limit, offset = options[:limit], options[:offset] if limit && offset sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" elsif limit sql << " LIMIT #{sanitize_limit(limit)}" elsif offset + limit = 18446744073709551615 if limit.nil? sql << " LIMIT #{sanitize_limit(limit)} OFFSET #{offset.to_i}" end sql From 445fa89fc8ce1ab20505d6f3f5316a682bb58fa1 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 21 Feb 2013 15:45:14 -0600 Subject: [PATCH 21/40] bump version to 0.2.19b6 --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 68c0f0cb8..f50e1cb8e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19b5) + mysql2 (0.2.19b6) GEM remote: http://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 6e547b235..f041d149c 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19b5" + VERSION = "0.2.19b6" end From f668ce408960cb11d21a26164be8e6209a2bee36 Mon Sep 17 00:00:00 2001 From: osheroff Date: Wed, 9 May 2012 12:04:36 -0700 Subject: [PATCH 22/40] symbolize keys sooner --- lib/active_record/connection_adapters/mysql2_adapter.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb index dc0172781..c9b8f101d 100644 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -5,13 +5,15 @@ module ActiveRecord class Base def self.mysql2_connection(config) + config = config.symbolize_keys + config[:username] = 'root' if config[:username].nil? if Mysql2::Client.const_defined? :FOUND_ROWS config[:flags] = Mysql2::Client::FOUND_ROWS end - client = Mysql2::Client.new(config.symbolize_keys) + client = Mysql2::Client.new(config) options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0] ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) end From 901b308606d5811725e55b74e3ece32793c819aa Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Tue, 9 Jul 2013 16:17:31 -0700 Subject: [PATCH 23/40] Remove EM/fiber support from this gem Support has moved to the em-synchrony gem. --- .../connection_adapters/em_mysql2_adapter.rb | 64 --------- lib/active_record/fiber_patches.rb | 132 ------------------ lib/mysql2/em_fiber.rb | 31 ---- spec/em/em_fiber_spec.rb | 22 --- 4 files changed, 249 deletions(-) delete mode 100644 lib/active_record/connection_adapters/em_mysql2_adapter.rb delete mode 100644 lib/active_record/fiber_patches.rb delete mode 100644 lib/mysql2/em_fiber.rb delete mode 100644 spec/em/em_fiber_spec.rb diff --git a/lib/active_record/connection_adapters/em_mysql2_adapter.rb b/lib/active_record/connection_adapters/em_mysql2_adapter.rb deleted file mode 100644 index 5deb575fb..000000000 --- a/lib/active_record/connection_adapters/em_mysql2_adapter.rb +++ /dev/null @@ -1,64 +0,0 @@ -# encoding: utf-8 - -# AR adapter for using a fibered mysql2 connection with EM -# This adapter should be used within Thin or Unicorn with the rack-fiber_pool middleware. -# Just update your database.yml's adapter to be 'em_mysql2' - -module ActiveRecord - class Base - def self.em_mysql2_connection(config) - client = ::Mysql2::Fibered::Client.new(config.symbolize_keys) - options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0] - ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) - end - end -end - -require 'fiber' -require 'eventmachine' -require 'mysql2' -require 'active_record/connection_adapters/mysql2_adapter' -require 'active_record/fiber_patches' - -module Mysql2 - module Fibered - class Client < ::Mysql2::Client - module Watcher - def initialize(client, deferable) - @client = client - @deferable = deferable - end - - def notify_readable - begin - detach - results = @client.async_result - @deferable.succeed(results) - rescue Exception => e - @deferable.fail(e) - end - end - end - - def query(sql, opts={}) - if ::EM.reactor_running? - super(sql, opts.merge(:async => true)) - deferrable = ::EM::DefaultDeferrable.new - ::EM.watch(self.socket, Watcher, self, deferrable).notify_readable = true - fiber = Fiber.current - deferrable.callback do |result| - fiber.resume(result) - end - deferrable.errback do |err| - fiber.resume(err) - end - Fiber.yield.tap do |result| - raise result if result.is_a?(Exception) - end - else - super(sql, opts) - end - end - end - end -end \ No newline at end of file diff --git a/lib/active_record/fiber_patches.rb b/lib/active_record/fiber_patches.rb deleted file mode 100644 index d2c22233d..000000000 --- a/lib/active_record/fiber_patches.rb +++ /dev/null @@ -1,132 +0,0 @@ -# Necessary monkeypatching to make AR fiber-friendly. - -module ActiveRecord - module ConnectionAdapters - - def self.fiber_pools - @fiber_pools ||= [] - end - def self.register_fiber_pool(fp) - fiber_pools << fp - end - - class FiberedMonitor - class Queue - def initialize - @queue = [] - end - - def wait(timeout) - t = timeout || 5 - fiber = Fiber.current - x = EM::Timer.new(t) do - @queue.delete(fiber) - fiber.resume(false) - end - @queue << fiber - Fiber.yield.tap do - x.cancel - end - end - - def signal - fiber = @queue.pop - fiber.resume(true) if fiber - end - end - - def synchronize - yield - end - - def new_cond - Queue.new - end - end - - # ActiveRecord's connection pool is based on threads. Since we are working - # with EM and a single thread, multiple fiber design, we need to provide - # our own connection pool that keys off of Fiber.current so that different - # fibers running in the same thread don't try to use the same connection. - class ConnectionPool - def initialize(spec) - @spec = spec - - # The cache of reserved connections mapped to threads - @reserved_connections = {} - - # The mutex used to synchronize pool access - @connection_mutex = FiberedMonitor.new - @queue = @connection_mutex.new_cond - - # default 5 second timeout unless on ruby 1.9 - @timeout = spec.config[:wait_timeout] || 5 - - # default max pool size to 5 - @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5 - - @connections = [] - @checked_out = [] - @automatic_reconnect = true - @tables = {} - - @columns = Hash.new do |h, table_name| - h[table_name] = with_connection do |conn| - - # Fetch a list of columns - conn.columns(table_name, "#{table_name} Columns").tap do |columns| - - # set primary key information - columns.each do |column| - column.primary = column.name == primary_keys[table_name] - end - end - end - end - - @columns_hash = Hash.new do |h, table_name| - h[table_name] = Hash[columns[table_name].map { |col| - [col.name, col] - }] - end - - @primary_keys = Hash.new do |h, table_name| - h[table_name] = with_connection do |conn| - table_exists?(table_name) ? conn.primary_key(table_name) : 'id' - end - end - end - - def clear_stale_cached_connections! - cache = @reserved_connections - keys = Set.new(cache.keys) - - ActiveRecord::ConnectionAdapters.fiber_pools.each do |pool| - pool.busy_fibers.each_pair do |object_id, fiber| - keys.delete(object_id) - end - end - - keys.each do |key| - next unless cache.has_key?(key) - checkin cache[key] - cache.delete(key) - end - end - - private - - def current_connection_id #:nodoc: - Fiber.current.object_id - end - - def checkout_and_verify(c) - @checked_out << c - c.run_callbacks :checkout - c.verify! - c - end - end - - end -end diff --git a/lib/mysql2/em_fiber.rb b/lib/mysql2/em_fiber.rb deleted file mode 100644 index 36cfddad6..000000000 --- a/lib/mysql2/em_fiber.rb +++ /dev/null @@ -1,31 +0,0 @@ -# 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.tap do |result| - raise result if result.is_a?(::Exception) - end - else - super(sql, opts) - end - end - end - end - end -end diff --git a/spec/em/em_fiber_spec.rb b/spec/em/em_fiber_spec.rb deleted file mode 100644 index 4d51e9958..000000000 --- a/spec/em/em_fiber_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# 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 DatabaseCredentials['root'] - 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 From 4f7a66e8ae0474b3a88c56eb2323370b653b9bfc Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Mon, 15 Jul 2013 16:06:34 -0700 Subject: [PATCH 24/40] bump version for 0.2.19 release --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7c039e916..f64d17ffe 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19b6) + mysql2 (0.2.19) GEM remote: https://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index f041d149c..4e6b12ba1 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19b6" + VERSION = "0.2.19" end From ef3c82e5530d183d239bf969adb313406a810192 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Wed, 17 Jul 2013 15:09:08 -0700 Subject: [PATCH 25/40] bump version for 0.2.20 release --- Gemfile.lock | 2 +- lib/mysql2/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f7d8c71c1..e8b2a4054 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - mysql2 (0.2.19) + mysql2 (0.2.20) GEM remote: https://rubygems.org/ diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 4e6b12ba1..1fd94760d 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.19" + VERSION = "0.2.20" end From 611f64cea271964a3c9971a9afa69db5bbd87d89 Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 7 Nov 2013 14:36:38 -0800 Subject: [PATCH 26/40] bump for 0.2.21 release --- lib/mysql2/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 1fd94760d..2902466bb 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.20" + VERSION = "0.2.21" end From 3c7548851f5bf124eb23307286ef95d61172ac4b Mon Sep 17 00:00:00 2001 From: Brian Lopez Date: Thu, 23 Jan 2014 15:54:21 -0800 Subject: [PATCH 27/40] bump version for 0.2.22 release --- lib/mysql2/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 2902466bb..5211a1683 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.21" + VERSION = "0.2.22" end From 30b2592f5b6ab2d4e2b96907d20ffe304142832c Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Tue, 13 May 2014 17:14:47 -0700 Subject: [PATCH 28/40] Bump version to 0.2.23 (matching 0.3.16) --- lib/mysql2/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 5211a1683..005394a9d 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.22" + VERSION = "0.2.23" end From 4ae5366bba0be1711fa64cd243591593a1260bc8 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 4 Aug 2014 13:09:24 -0700 Subject: [PATCH 29/40] Rather than keeping the CHARSET_MAP hack around, through thick and thin, just hack the generated charset mapping to force mysql latin1 to ruby utf8 --- ext/mysql2/mysql_enc_name_to_ruby.h | 2 +- ext/mysql2/mysql_enc_to_ruby.h | 16 ++++++++-------- lib/mysql2/version.rb | 2 +- support/mysql_enc_to_ruby.rb | 2 +- support/ruby_enc_to_mysql.rb | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ext/mysql2/mysql_enc_name_to_ruby.h b/ext/mysql2/mysql_enc_name_to_ruby.h index dfabeef1f..36f66fbe4 100644 --- a/ext/mysql2/mysql_enc_name_to_ruby.h +++ b/ext/mysql2/mysql_enc_name_to_ruby.h @@ -122,7 +122,7 @@ mysql2_mysql_enc_name_to_rb (str, len) {"macroman", "macRoman"}, {"dec8", NULL}, {"utf32", "UTF-32"}, - {"latin1", "ISO-8859-1"}, + {"latin1", "UTF-8"}, {"utf8mb4", "UTF-8"}, {"hp8", NULL}, {"swe7", NULL}, diff --git a/ext/mysql2/mysql_enc_to_ruby.h b/ext/mysql2/mysql_enc_to_ruby.h index 37dbf6f73..1eb13cec0 100644 --- a/ext/mysql2/mysql_enc_to_ruby.h +++ b/ext/mysql2/mysql_enc_to_ruby.h @@ -3,17 +3,17 @@ const char *mysql2_mysql_enc_to_rb[] = { "ISO-8859-2", NULL, "CP850", - "ISO-8859-1", + "UTF-8", NULL, "KOI8-R", - "ISO-8859-1", + "UTF-8", "ISO-8859-2", NULL, "US-ASCII", "eucJP-ms", "Shift_JIS", "Windows-1251", - "ISO-8859-1", + "UTF-8", "ISO-8859-8", NULL, "TIS-620", @@ -29,7 +29,7 @@ const char *mysql2_mysql_enc_to_rb[] = { "GBK", "Windows-1257", "ISO-8859-9", - "ISO-8859-1", + "UTF-8", NULL, "UTF-8", "Windows-1250", @@ -45,9 +45,9 @@ const char *mysql2_mysql_enc_to_rb[] = { "Windows-1250", "UTF-8", "UTF-8", - "ISO-8859-1", - "ISO-8859-1", - "ISO-8859-1", + "UTF-8", + "UTF-8", + "UTF-8", "Windows-1251", "Windows-1251", "Windows-1251", @@ -92,7 +92,7 @@ const char *mysql2_mysql_enc_to_rb[] = { "eucJP-ms", NULL, NULL, - "ISO-8859-1", + "UTF-8", "Windows-31J", "Windows-31J", "eucJP-ms", diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 005394a9d..ad746931d 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.23" + VERSION = "0.2.23.latin1utf8" end diff --git a/support/mysql_enc_to_ruby.rb b/support/mysql_enc_to_ruby.rb index 4a3ef70db..8228d5776 100644 --- a/support/mysql_enc_to_ruby.rb +++ b/support/mysql_enc_to_ruby.rb @@ -9,7 +9,7 @@ "cp850" => "CP850", "hp8" => "NULL", "koi8r" => "KOI8-R", - "latin1" => "ISO-8859-1", + "latin1" => "UTF-8", "latin2" => "ISO-8859-2", "swe7" => "NULL", "ascii" => "US-ASCII", diff --git a/support/ruby_enc_to_mysql.rb b/support/ruby_enc_to_mysql.rb index 112016c94..856bc0e76 100644 --- a/support/ruby_enc_to_mysql.rb +++ b/support/ruby_enc_to_mysql.rb @@ -4,7 +4,7 @@ "cp850" => "CP850", "hp8" => nil, "koi8r" => "KOI8-R", - "latin1" => "ISO-8859-1", + "latin1" => "UTF-8", "latin2" => "ISO-8859-2", "swe7" => nil, "ascii" => "US-ASCII", From 267a53887cb52f799d6a84f08cd1664bf6288f86 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Tue, 11 Nov 2014 11:00:14 -0800 Subject: [PATCH 30/40] Bump version to 0.2.24 --- lib/mysql2/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mysql2/version.rb b/lib/mysql2/version.rb index 005394a9d..dff849ff2 100644 --- a/lib/mysql2/version.rb +++ b/lib/mysql2/version.rb @@ -1,3 +1,3 @@ module Mysql2 - VERSION = "0.2.23" + VERSION = "0.2.24" end From c920d41e43c4722d4c065d2ea9d21494c560bd85 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Wed, 28 Jun 2017 23:00:12 -0400 Subject: [PATCH 31/40] Fix for MariaDB 10.2 which does not define CLIENT_LONG_PASSWORD --- ext/mysql2/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 5d75304b4..bb344b209 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1297,6 +1297,10 @@ void init_mysql2_client() { #ifdef CLIENT_LONG_PASSWORD rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), LONG2NUM(CLIENT_LONG_PASSWORD)); +#else + /* HACK because MariaDB 10.2 no longer defines this constant, + * but we're using it in our default connection flags. */ + rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0)); #endif #ifdef CLIENT_FOUND_ROWS From c23ef729ae34ef2e675504d4f8d16643970de203 Mon Sep 17 00:00:00 2001 From: John Conroy Date: Tue, 8 Sep 2015 18:00:22 -0400 Subject: [PATCH 32/40] Only do version check in Windows environment Unix systems using libtool do not need to do a version check against the client version string as the libraries themselves are versioned. --- ext/mysql2/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index bb344b209..9e12784a6 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1210,6 +1210,7 @@ static VALUE initialize_ext(VALUE self) { } void init_mysql2_client() { +#ifdef _WIN32 /* verify the libmysql we're about to use was the version we were built against https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99 */ int i; @@ -1227,6 +1228,7 @@ void init_mysql2_client() { return; } } +#endif /* Initializing mysql library, so different threads could call Client.new */ /* without race condition in the library */ From 428e1b6d80a1eabba2c4128969f35962e6978291 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Nov 2017 09:33:37 -0500 Subject: [PATCH 33/40] MYSQL_SECURE_AUTH has been removed in MySQL 8.0.3 RC (#892) https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-3.html#mysqld-8-0-3-capi > The deprecated secure_auth system variable and --secure-auth client option have been removed. > The MYSQL_SECURE_AUTH option for the mysql_options() C API function was removed. --- ext/mysql2/client.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index bb344b209..dc4ecc4ae 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -794,10 +794,12 @@ static VALUE _mysql_client_options(VALUE self, int opt, VALUE value) { retval = &boolval; break; +#if defined(MYSQL_SECURE_AUTH) case MYSQL_SECURE_AUTH: boolval = (value == Qfalse ? 0 : 1); retval = &boolval; break; +#endif case MYSQL_READ_DEFAULT_FILE: charval = (const char *)StringValueCStr(value); @@ -1182,7 +1184,10 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE } static VALUE set_secure_auth(VALUE self, VALUE value) { +/* This option was deprecated in MySQL 5.x and removed in MySQL 8.0 */ +#if defined(MYSQL_SECURE_AUTH) return _mysql_client_options(self, MYSQL_SECURE_AUTH, value); +#endif } static VALUE set_read_default_file(VALUE self, VALUE value) { From 288ba84044ea0826c25d5f97828aebb81237eb83 Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Sun, 3 Dec 2017 08:14:44 -0800 Subject: [PATCH 34/40] Use a typedef my_bool to improve compatibility across MySQL versions MySQL 8.0 replaces my_bool with C99 bool. Earlier versions of MySQL had a typedef to char. Gem users reported failures on big endian systems when using C99 bool types with older MySQLs due to mismatched behavior. --- ext/mysql2/extconf.rb | 6 ++++++ ext/mysql2/mysql2_ext.h | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 8590da386..3d1d75b2b 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -111,6 +111,12 @@ def asplode lib $CFLAGS << gcc_flags end +mysql_h = [prefix, 'mysql.h'].compact.join('/') + +# my_bool is replaced by C99 bool in MySQL 8.0, but we want +# to retain compatibility with the typedef in earlier MySQLs. +have_type('my_bool', mysql_h) + if RUBY_PLATFORM =~ /mswin|mingw/ # Build libmysql.a interface link library require 'rake' diff --git a/ext/mysql2/mysql2_ext.h b/ext/mysql2/mysql2_ext.h index d6d5fd626..7d68ef5ba 100644 --- a/ext/mysql2/mysql2_ext.h +++ b/ext/mysql2/mysql2_ext.h @@ -38,6 +38,14 @@ typedef unsigned int uint; #define RB_MYSQL_UNUSED #endif +/* MySQL 8.0 replaces my_bool with C99 bool. Earlier versions of MySQL had + * a typedef to char. Gem users reported failures on big endian systems when + * using C99 bool types with older MySQLs due to mismatched behavior. */ +#ifndef HAVE_TYPE_MY_BOOL +#include +typedef bool my_bool; +#endif + #include #include #include From cdd6eb42070c23149a01a5c2d28c2b8965c876ab Mon Sep 17 00:00:00 2001 From: John Conroy Date: Tue, 8 Sep 2015 18:00:22 -0400 Subject: [PATCH 35/40] Only do version check in Windows environment Unix systems using libtool do not need to do a version check against the client version string as the libraries themselves are versioned. --- ext/mysql2/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 85dfc65a8..0d66d88d3 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1221,6 +1221,7 @@ static VALUE initialize_ext(VALUE self) { } void init_mysql2_client() { +#ifdef _WIN32 /* verify the libmysql we're about to use was the version we were built against https://github.com/luislavena/mysql-gem/commit/a600a9c459597da0712f70f43736e24b484f8a99 */ int i; @@ -1238,6 +1239,7 @@ void init_mysql2_client() { return; } } +#endif /* Initializing mysql library, so different threads could call Client.new */ /* without race condition in the library */ From a09b412aa032915fe3d3d96ae9eb6fb4c0f0ccfb Mon Sep 17 00:00:00 2001 From: Aaron Stone Date: Wed, 28 Jun 2017 23:00:12 -0400 Subject: [PATCH 36/40] Fix for MariaDB 10.2 which does not define CLIENT_LONG_PASSWORD --- ext/mysql2/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ext/mysql2/client.c b/ext/mysql2/client.c index 0d66d88d3..dfad1b237 100644 --- a/ext/mysql2/client.c +++ b/ext/mysql2/client.c @@ -1309,6 +1309,10 @@ void init_mysql2_client() { #ifdef CLIENT_LONG_PASSWORD rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), LONG2NUM(CLIENT_LONG_PASSWORD)); +#else + /* HACK because MariaDB 10.2 no longer defines this constant, + * but we're using it in our default connection flags. */ + rb_const_set(cMysql2Client, rb_intern("LONG_PASSWORD"), INT2NUM(0)); #endif #ifdef CLIENT_FOUND_ROWS From f5c50ef895703c516ae1b2cbbdf2b205b52fb211 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 5 May 2015 14:53:52 +0300 Subject: [PATCH 37/40] Also search for mariadb_config on compile libmariadb-client-lgpl-dev in newly released Debian stable (jessie) ships `/usr/bin/mariadb_config`. --- ext/mysql2/extconf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql2/extconf.rb b/ext/mysql2/extconf.rb index 9895f5999..eabe7aa02 100644 --- a/ext/mysql2/extconf.rb +++ b/ext/mysql2/extconf.rb @@ -29,7 +29,7 @@ def asplode lib /usr/local/lib/mysql5 ].map{|dir| "#{dir}/bin" } -GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5}" +GLOB = "{#{dirs.join(',')}}/{mysql_config,mysql_config5,mariadb_config}" # If the user has provided a --with-mysql-dir argument, we must respect it or fail. inc, lib = dir_config('mysql') From e23d40ed7487554f753b8621bcc1f8befdee46d8 Mon Sep 17 00:00:00 2001 From: Lewis Buckley Date: Wed, 29 Mar 2023 09:16:51 +0100 Subject: [PATCH 38/40] Support microseconds See also https://github.com/makandra/mysql2/commit/56b46c8b88c9e720d08b743d9b43154ad09484c3 --- ext/mysql2/result.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/mysql2/result.c b/ext/mysql2/result.c index 5b8a5b162..9054ed545 100644 --- a/ext/mysql2/result.c +++ b/ext/mysql2/result.c @@ -297,7 +297,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo break; } msec = msec_char_to_uint(msec_char, sizeof(msec_char)); - val = rb_funcall(rb_cTime, db_timezone, 6, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec)); + val = rb_funcall(rb_cTime, db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec)); if (!NIL_P(app_timezone)) { if (app_timezone == intern_local) { val = rb_funcall(val, intern_localtime, 0); From c55cb2509423032bd228a31fb0312de7583d9942 Mon Sep 17 00:00:00 2001 From: Lewis Buckley Date: Fri, 31 Mar 2023 14:18:29 +0100 Subject: [PATCH 39/40] Remove mysql2 adapter which is part of Rails 3.2 --- .../connection_adapters/mysql2_adapter.rb | 635 ------------------ 1 file changed, 635 deletions(-) delete mode 100644 lib/active_record/connection_adapters/mysql2_adapter.rb diff --git a/lib/active_record/connection_adapters/mysql2_adapter.rb b/lib/active_record/connection_adapters/mysql2_adapter.rb deleted file mode 100644 index c9b8f101d..000000000 --- a/lib/active_record/connection_adapters/mysql2_adapter.rb +++ /dev/null @@ -1,635 +0,0 @@ -# encoding: utf-8 - -require 'mysql2' - -module ActiveRecord - class Base - def self.mysql2_connection(config) - config = config.symbolize_keys - - config[:username] = 'root' if config[:username].nil? - - if Mysql2::Client.const_defined? :FOUND_ROWS - config[:flags] = Mysql2::Client::FOUND_ROWS - end - - client = Mysql2::Client.new(config) - options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0] - ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) - end - end - - module ConnectionAdapters - class Mysql2IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths) #:nodoc: - end - - class Mysql2Column < Column - BOOL = "tinyint(1)" - def extract_default(default) - if sql_type =~ /blob/i || type == :text - if default.blank? - return null ? nil : '' - else - raise ArgumentError, "#{type} columns cannot have a default value: #{default.inspect}" - end - elsif missing_default_forged_as_empty_string?(default) - nil - else - super - end - end - - def has_default? - return false if sql_type =~ /blob/i || type == :text # mysql forbids defaults on blob and text columns - super - end - - private - def simplified_type(field_type) - return :boolean if Mysql2Adapter.emulate_booleans && field_type.downcase.index(BOOL) - return :string if field_type =~ /enum/i or field_type =~ /set/i - return :integer if field_type =~ /year/i - return :binary if field_type =~ /bit/i - super - end - - def extract_limit(sql_type) - case sql_type - when /blob|text/i - case sql_type - when /tiny/i - 255 - when /medium/i - 16777215 - when /long/i - 2147483647 # mysql only allows 2^31-1, not 2^32-1, somewhat inconsistently with the tiny/medium/normal cases - else - super # we could return 65535 here, but we leave it undecorated by default - end - when /^bigint/i; 8 - when /^int/i; 4 - when /^mediumint/i; 3 - when /^smallint/i; 2 - when /^tinyint/i; 1 - else - super - end - end - - # MySQL misreports NOT NULL column default when none is given. - # We can't detect this for columns which may have a legitimate '' - # default (string) but we can for others (integer, datetime, boolean, - # and the rest). - # - # Test whether the column has default '', is not null, and is not - # a type allowing default ''. - def missing_default_forged_as_empty_string?(default) - type != :string && !null && default == '' - end - end - - class Mysql2Adapter < AbstractAdapter - cattr_accessor :emulate_booleans - self.emulate_booleans = true - - ADAPTER_NAME = 'Mysql2' - PRIMARY = "PRIMARY" - - LOST_CONNECTION_ERROR_MESSAGES = [ - "Server shutdown in progress", - "Broken pipe", - "Lost connection to MySQL server during query", - "MySQL server has gone away" ] - - QUOTED_TRUE, QUOTED_FALSE = '1', '0' - - NATIVE_DATABASE_TYPES = { - :primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY", - :string => { :name => "varchar", :limit => 255 }, - :text => { :name => "text" }, - :integer => { :name => "int", :limit => 4 }, - :float => { :name => "float" }, - :decimal => { :name => "decimal" }, - :datetime => { :name => "datetime" }, - :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, - :date => { :name => "date" }, - :binary => { :name => "blob" }, - :boolean => { :name => "tinyint", :limit => 1 } - } - - def initialize(connection, logger, connection_options, config) - super(connection, logger) - @connection_options, @config = connection_options, config - @quoted_column_names, @quoted_table_names = {}, {} - configure_connection - end - - def adapter_name - ADAPTER_NAME - end - - def supports_migrations? - true - end - - def supports_primary_key? - true - end - - def supports_savepoints? - true - end - - def native_database_types - NATIVE_DATABASE_TYPES - end - - # QUOTING ================================================== - - def quote(value, column = nil) - if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) - s = column.class.string_to_binary(value).unpack("H*")[0] - "x'#{s}'" - else - super - end - end - - def quote_column_name(name) #:nodoc: - @quoted_column_names[name] ||= "`#{name.to_s.gsub('`', '``')}`" - end - - def quote_table_name(name) #:nodoc: - @quoted_table_names[name] ||= quote_column_name(name).gsub('.', '`.`') - end - - def quote_string(string) - @connection.escape(string) - end - - def quoted_true - QUOTED_TRUE - end - - def quoted_false - QUOTED_FALSE - end - - # REFERENTIAL INTEGRITY ==================================== - - def disable_referential_integrity(&block) #:nodoc: - old = select_value("SELECT @@FOREIGN_KEY_CHECKS") - - begin - update("SET FOREIGN_KEY_CHECKS = 0") - yield - ensure - update("SET FOREIGN_KEY_CHECKS = #{old}") - end - end - - # CONNECTION MANAGEMENT ==================================== - - def active? - return false unless @connection - @connection.ping - end - - def reconnect! - disconnect! - connect - end - - # this is set to true in 2.3, but we don't want it to be - def requires_reloading? - false - end - - def disconnect! - unless @connection.nil? - @connection.close - @connection = nil - end - end - - def reset! - disconnect! - connect - end - - # DATABASE STATEMENTS ====================================== - - # FIXME: re-enable the following once a "better" query_cache solution is in core - # - # The overrides below perform much better than the originals in AbstractAdapter - # because we're able to take advantage of mysql2's lazy-loading capabilities - # - # # Returns a record hash with the column names as keys and column values - # # as values. - # def select_one(sql, name = nil) - # result = execute(sql, name) - # result.each(:as => :hash) do |r| - # return r - # end - # end - # - # # Returns a single value from a record - # def select_value(sql, name = nil) - # result = execute(sql, name) - # if first = result.first - # first.first - # end - # end - # - # # Returns an array of the values of the first column in a select: - # # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3] - # def select_values(sql, name = nil) - # execute(sql, name).map { |row| row.first } - # end - - # Returns an array of arrays containing the field values. - # Order is the same as that returned by +columns+. - def select_rows(sql, name = nil) - execute(sql, name).to_a - end - - # Executes the SQL statement in the context of this connection. - def execute(sql, name = nil) - # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been - # made since we established the connection - @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone - if name == :skip_logging - @connection.query(sql) - else - log(sql, name) { @connection.query(sql) } - end - rescue ActiveRecord::StatementInvalid => exception - if exception.message.split(":").first =~ /Packets out of order/ - raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings." - else - raise - end - end - - def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) - super - id_value || @connection.last_id - end - alias :create :insert_sql - - def update_sql(sql, name = nil) - super - @connection.affected_rows - end - - def begin_db_transaction - execute "BEGIN" - rescue Exception - # Transactions aren't supported - end - - def commit_db_transaction - execute "COMMIT" - rescue Exception - # Transactions aren't supported - end - - def rollback_db_transaction - execute "ROLLBACK" - rescue Exception - # Transactions aren't supported - end - - def create_savepoint - execute("SAVEPOINT #{current_savepoint_name}") - end - - def rollback_to_savepoint - execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}") - end - - def release_savepoint - execute("RELEASE SAVEPOINT #{current_savepoint_name}") - end - - def add_limit_offset!(sql, options) - limit, offset = options[:limit], options[:offset] - if limit && offset - sql << " LIMIT #{offset.to_i}, #{sanitize_limit(limit)}" - elsif limit - sql << " LIMIT #{sanitize_limit(limit)}" - elsif offset - limit = 18446744073709551615 if limit.nil? - sql << " LIMIT #{sanitize_limit(limit)} OFFSET #{offset.to_i}" - end - sql - end - - # SCHEMA STATEMENTS ======================================== - - def structure_dump - if supports_views? - sql = "SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'" - else - sql = "SHOW TABLES" - end - - select_all(sql).inject("") do |structure, table| - table.delete('Table_type') - structure += select_one("SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}")["Create Table"] + ";\n\n" - end - end - - def recreate_database(name, options = {}) - drop_database(name) - create_database(name, options) - end - - # Create a new MySQL database with optional :charset and :collation. - # Charset defaults to utf8. - # - # Example: - # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' - # create_database 'matt_development' - # create_database 'matt_development', :charset => :big5 - def create_database(name, options = {}) - if options[:collation] - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`" - else - execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`" - end - end - - def drop_database(name) #:nodoc: - execute "DROP DATABASE IF EXISTS `#{name}`" - end - - def current_database - select_value 'SELECT DATABASE() as db' - end - - # Returns the database character set. - def charset - show_variable 'character_set_database' - end - - # Returns the database collation strategy. - def collation - show_variable 'collation_database' - end - - def tables(name = nil, database = nil) - tables = [] - - sql = "SHOW TABLES " - sql << "IN #{quote_table_name(database)} " if database - - execute(sql, 'SCHEMA').each do |field| - tables << field.first - end - tables - end - - def table_exists?(name) - return true if super - - name = name.to_s - schema, table = name.split('.', 2) - - unless table # A table was provided without a schema - table = schema - schema = nil - end - - tables(nil, schema).include? table - end - - def drop_table(table_name, options = {}) - super(table_name, options) - end - - def indexes(table_name, name = nil) - indexes = [] - current_index = nil - result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name) - result.each(:symbolize_keys => true, :as => :hash) do |row| - if current_index != row[:Key_name] - next if row[:Key_name] == PRIMARY # skip the primary key - current_index = row[:Key_name] - indexes << Mysql2IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [], []) - end - - indexes.last.columns << row[:Column_name] - indexes.last.lengths << row[:Sub_part] - end - indexes - end - - def columns(table_name, name = nil) - sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}" - columns = [] - result = execute(sql, :skip_logging) - result.each(:symbolize_keys => true, :as => :hash) { |field| - columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES") - } - columns - end - - def create_table(table_name, options = {}) - super(table_name, options.reverse_merge(:options => "ENGINE=InnoDB")) - end - - def rename_table(table_name, new_name) - execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}" - end - - def add_column(table_name, column_name, type, options = {}) - add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(add_column_sql, options) - add_column_position!(add_column_sql, options) - execute(add_column_sql) - end - - def change_column_default(table_name, column_name, default) - column = column_for(table_name, column_name) - change_column table_name, column_name, column.sql_type, :default => default - end - - def change_column_null(table_name, column_name, null, default = nil) - column = column_for(table_name, column_name) - - unless null || default.nil? - execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL") - end - - change_column table_name, column_name, column.sql_type, :null => null - end - - def change_column(table_name, column_name, type, options = {}) - column = column_for(table_name, column_name) - - unless options_include_default?(options) - options[:default] = column.default - end - - unless options.has_key?(:null) - options[:null] = column.null - end - - change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" - add_column_options!(change_column_sql, options) - add_column_position!(change_column_sql, options) - execute(change_column_sql) - end - - def rename_column(table_name, column_name, new_column_name) - options = {} - if column = columns(table_name).find { |c| c.name == column_name.to_s } - options[:default] = column.default - options[:null] = column.null - else - raise ActiveRecordError, "No such column: #{table_name}.#{column_name}" - end - current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'")["Type"] - rename_column_sql = "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}" - add_column_options!(rename_column_sql, options) - execute(rename_column_sql) - end - - # Maps logical Rails types to MySQL-specific data types. - def type_to_sql(type, limit = nil, precision = nil, scale = nil) - case type.to_s - when 'integer' - case limit - when 1; 'tinyint' - when 2; 'smallint' - when 3; 'mediumint' - when nil, 4, 11; 'int(11)' # compatibility with MySQL default - when 5..8; 'bigint' - else raise(ActiveRecordError, "No integer type has byte size #{limit}") - end - when 'text' - case limit - when 0..0xff; 'tinytext' - when nil, 0x100..0xffff; 'text' - when 0x10000..0xffffff; 'mediumtext' - when 0x1000000..0xffffffff; 'longtext' - else raise(ActiveRecordError, "No text type has character length #{limit}") - end - else - super - end - end - - def add_column_position!(sql, options) - if options[:first] - sql << " FIRST" - elsif options[:after] - sql << " AFTER #{quote_column_name(options[:after])}" - end - end - - def show_variable(name) - variables = select_all("SHOW VARIABLES LIKE '#{name}'") - variables.first['Value'] unless variables.empty? - end - - def pk_and_sequence_for(table) - keys = [] - result = execute("describe #{quote_table_name(table)}") - result.each(:symbolize_keys => true, :as => :hash) do |row| - keys << row[:Field] if row[:Key] == "PRI" - end - keys.length == 1 ? [keys.first, nil] : nil - end - - # Returns just a table's primary key - def primary_key(table) - pk_and_sequence = pk_and_sequence_for(table) - pk_and_sequence && pk_and_sequence.first - end - - def case_sensitive_equality_operator - "= BINARY" - end - - def limited_update_conditions(where_sql, quoted_table_name, quoted_primary_key) - where_sql - end - - protected - def quoted_columns_for_index(column_names, options = {}) - length = options[:length] if options.is_a?(Hash) - - quoted_column_names = case length - when Hash - column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } - when Fixnum - column_names.map {|name| "#{quote_column_name(name)}(#{length})"} - else - column_names.map {|name| quote_column_name(name) } - end - end - - def translate_exception(exception, message) - return super unless exception.respond_to?(:error_number) - - case exception.error_number - when 1062 - RecordNotUnique.new(message, exception) - when 1452 - InvalidForeignKey.new(message, exception) - else - super - end - end - - private - def connect - @connection = Mysql2::Client.new(@config) - configure_connection - end - - def configure_connection - @connection.query_options.merge!(:as => :array) - - # By default, MySQL 'where id is null' selects the last inserted id. - # Turn this off. http://dev.rubyonrails.org/ticket/6778 - variable_assignments = ['SQL_AUTO_IS_NULL=0'] - encoding = @config[:encoding] - - # make sure we set the encoding - variable_assignments << "NAMES '#{encoding}'" if encoding - - # increase timeout so mysql server doesn't disconnect us - wait_timeout = @config[:wait_timeout] - wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum) - variable_assignments << "@@wait_timeout = #{wait_timeout}" - - execute("SET #{variable_assignments.join(', ')}", :skip_logging) - end - - # Returns an array of record hashes with the column names as keys and - # column values as values. - def select(sql, name = nil) - execute(sql, name).each(:as => :hash) - end - - def supports_views? - version[0] >= 5 - end - - def version - @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } - end - - def column_for(table_name, column_name) - unless column = columns(table_name).find { |c| c.name == column_name.to_s } - raise "No such column: #{table_name}.#{column_name}" - end - column - end - end - end -end From beb78d50f6b33754adb1eb4df123b0130d4ac04e Mon Sep 17 00:00:00 2001 From: Lewis Buckley Date: Fri, 31 Mar 2023 14:29:27 +0100 Subject: [PATCH 40/40] Match makandra 0.3.x lts --- lib/arel/engines/sql/compilers/mysql2_compiler.rb | 11 ----------- lib/mysql2.rb | 15 ++++++++++----- 2 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 lib/arel/engines/sql/compilers/mysql2_compiler.rb diff --git a/lib/arel/engines/sql/compilers/mysql2_compiler.rb b/lib/arel/engines/sql/compilers/mysql2_compiler.rb deleted file mode 100644 index 4b8998ff3..000000000 --- a/lib/arel/engines/sql/compilers/mysql2_compiler.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Arel - module SqlCompiler - class Mysql2Compiler < GenericCompiler - def limited_update_conditions(conditions, taken) - conditions << " LIMIT #{taken}" - conditions - end - end - end -end - diff --git a/lib/mysql2.rb b/lib/mysql2.rb index 1b222f6ee..6722d8209 100644 --- a/lib/mysql2.rb +++ b/lib/mysql2.rb @@ -38,11 +38,16 @@ module Mysql2 end -if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING >= "3.1" - warn "============= WARNING FROM mysql2 =============" - warn "This version of mysql2 (#{Mysql2::VERSION}) isn't compatible with Rails 3.1 as the ActiveRecord adapter was pulled into Rails itself." - warn "Please use the 0.3.x (or greater) releases if you plan on using it in Rails >= 3.1.x" - warn "============= END WARNING FROM mysql2 =============" +if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3.1" + begin + require 'active_record/connection_adapters/mysql2_adapter' + rescue LoadError + warn "============= WARNING FROM mysql2 =============" + warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter." + warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails." + warn "If you want to use the mysql2 gem with Rails <= 3.0.x, please use the latest mysql2 in the 0.2.x series." + warn "============= END WARNING FROM mysql2 =============" + end end # For holding utility methods