mysql2 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +9 -0
- data/README.rdoc +1 -1
- data/Rakefile +0 -37
- data/VERSION +1 -1
- data/ext/mysql2/client.c +44 -36
- data/ext/mysql2/extconf.rb +1 -1
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +7 -0
- data/lib/mysql2.rb +1 -1
- data/lib/mysql2/client.rb +3 -2
- data/lib/mysql2/em.rb +1 -1
- data/mysql2.gemspec +5 -4
- data/spec/em/em_spec.rb +42 -19
- data/spec/mysql2/client_spec.rb +57 -19
- data/spec/spec_helper.rb +3 -2
- data/tasks/compile.rake +29 -7
- data/tasks/jeweler.rake +17 -0
- data/tasks/rspec.rake +16 -0
- metadata +7 -6
- data/benchmark/thread_alone.rb +0 -20
- data/spec/spec.opts +0 -2
data/.gitignore
CHANGED
data/.rspec
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.2.5 (October 19th, 2010)
|
4
|
+
* fixes for easier Win32 binary gem deployment for targeting 1.8 and 1.9 in the same gem
|
5
|
+
* refactor of connection checks and management to avoid race conditions with the GC/threading to prevent the unexpected loss of connections
|
6
|
+
* update the default flags during connection
|
7
|
+
* add support for setting wait_timeout on AR adapter
|
8
|
+
* upgrade to rspec2
|
9
|
+
* bugfix for an edge case where the GC would clean up a Mysql2::Client object before the underlying MYSQL pointer had been initialized
|
10
|
+
* fix to CFLAGS to allow compilation on SPARC with sunstudio compiler - Anko painting <anko.com+github@gmail.com>
|
11
|
+
|
3
12
|
## 0.2.4 (September 17th, 2010)
|
4
13
|
* a few patches for win32 support from Luis Lavena - thanks man!
|
5
14
|
* bugfix from Eric Wong to avoid a potential stack overflow during Mysql2::Client#escape
|
data/README.rdoc
CHANGED
@@ -234,7 +234,7 @@ then iterating over every row using an #each like method yielding a block:
|
|
234
234
|
|
235
235
|
== Special Thanks
|
236
236
|
|
237
|
-
* Eric Wong - for the contribution (and informative explanations
|
237
|
+
* Eric Wong - for the contribution (and the informative explanations) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
|
238
238
|
* Yury Korolev (http://github.com/yury) - for TONS of help testing the ActiveRecord adapter
|
239
239
|
* Aaron Patterson (http://github.com/tenderlove) - tons of contributions, suggestions and general badassness
|
240
240
|
* Mike Perham (http://github.com/mperham) - Async ActiveRecord adapter (uses Fibers and EventMachine)
|
data/Rakefile
CHANGED
@@ -1,42 +1,5 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
begin
|
3
|
-
require 'jeweler'
|
4
|
-
JEWELER = Jeweler::Tasks.new do |gem|
|
5
|
-
gem.name = "mysql2"
|
6
|
-
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
|
7
|
-
gem.email = "seniorlopez@gmail.com"
|
8
|
-
gem.homepage = "http://github.com/brianmario/mysql2"
|
9
|
-
gem.authors = ["Brian Lopez"]
|
10
|
-
gem.require_paths = ["lib", "ext"]
|
11
|
-
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
|
12
|
-
gem.files = `git ls-files`.split("\n")
|
13
|
-
gem.extensions = ["ext/mysql2/extconf.rb"]
|
14
|
-
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
|
15
|
-
# gem.rubyforge_project = "mysql2"
|
16
|
-
end
|
17
|
-
rescue LoadError
|
18
|
-
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler -s http://gems.github.com"
|
19
|
-
end
|
20
|
-
|
21
2
|
require 'rake'
|
22
|
-
require 'spec/rake/spectask'
|
23
|
-
|
24
|
-
desc "Run all examples with RCov"
|
25
|
-
Spec::Rake::SpecTask.new('spec:rcov') do |t|
|
26
|
-
t.spec_files = FileList['spec/']
|
27
|
-
t.rcov = true
|
28
|
-
t.rcov_opts = lambda do
|
29
|
-
IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
|
30
|
-
end
|
31
|
-
end
|
32
|
-
Spec::Rake::SpecTask.new('spec') do |t|
|
33
|
-
t.spec_files = FileList['spec/']
|
34
|
-
t.spec_opts << '--options' << 'spec/spec.opts'
|
35
|
-
t.verbose = true
|
36
|
-
t.warning = true
|
37
|
-
end
|
38
|
-
|
39
|
-
task :default => :spec
|
40
3
|
|
41
4
|
# Load custom tasks
|
42
5
|
Dir['tasks/*.rake'].sort.each { |f| load f }
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.5
|
data/ext/mysql2/client.c
CHANGED
@@ -9,7 +9,7 @@ static ID sym_id, sym_version, sym_async, sym_symbolize_keys, sym_as, sym_array;
|
|
9
9
|
static ID intern_merge, intern_error_number_eql, intern_sql_state_eql;
|
10
10
|
|
11
11
|
#define REQUIRE_OPEN_DB(wrapper) \
|
12
|
-
if(wrapper->closed
|
12
|
+
if(wrapper->closed) { \
|
13
13
|
rb_raise(cMysql2Error, "closed MySQL connection"); \
|
14
14
|
return Qnil; \
|
15
15
|
}
|
@@ -83,11 +83,11 @@ static VALUE rb_raise_mysql2_error(MYSQL *client) {
|
|
83
83
|
}
|
84
84
|
|
85
85
|
static VALUE nogvl_init(void *ptr) {
|
86
|
-
MYSQL
|
86
|
+
MYSQL *client;
|
87
87
|
|
88
88
|
/* may initialize embedded server and read /etc/services off disk */
|
89
|
-
|
90
|
-
return
|
89
|
+
client = mysql_init((MYSQL *)ptr);
|
90
|
+
return client ? Qtrue : Qfalse;
|
91
91
|
}
|
92
92
|
|
93
93
|
static VALUE nogvl_connect(void *ptr) {
|
@@ -104,54 +104,52 @@ static VALUE nogvl_connect(void *ptr) {
|
|
104
104
|
return client ? Qtrue : Qfalse;
|
105
105
|
}
|
106
106
|
|
107
|
-
static
|
108
|
-
mysql_client_wrapper *wrapper =
|
109
|
-
|
110
|
-
|
111
|
-
* we'll send a QUIT message to the server, but that message is more of a
|
112
|
-
* formality than a hard requirement since the socket is getting shutdown
|
113
|
-
* anyways, so ensure the socket write does not block our interpreter
|
114
|
-
*/
|
115
|
-
int fd = wrapper->client->net.fd;
|
107
|
+
static VALUE nogvl_close(void *ptr) {
|
108
|
+
mysql_client_wrapper *wrapper = ptr;
|
109
|
+
if (!wrapper->closed) {
|
110
|
+
wrapper->closed = 1;
|
116
111
|
|
117
|
-
if (fd >= 0) {
|
118
112
|
/*
|
113
|
+
* we'll send a QUIT message to the server, but that message is more of a
|
114
|
+
* formality than a hard requirement since the socket is getting shutdown
|
115
|
+
* anyways, so ensure the socket write does not block our interpreter
|
116
|
+
*
|
117
|
+
*
|
119
118
|
* if the socket is dead we have no chance of blocking,
|
120
119
|
* so ignore any potential fcntl errors since they don't matter
|
121
120
|
*/
|
122
121
|
#ifndef _WIN32
|
123
|
-
int flags = fcntl(fd, F_GETFL);
|
122
|
+
int flags = fcntl(wrapper->client->net.fd, F_GETFL);
|
124
123
|
if (flags > 0 && !(flags & O_NONBLOCK))
|
125
|
-
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
124
|
+
fcntl(wrapper->client->net.fd, F_SETFL, flags | O_NONBLOCK);
|
126
125
|
#else
|
127
126
|
u_long iMode = 1;
|
128
|
-
ioctlsocket(fd, FIONBIO, &iMode);
|
127
|
+
ioctlsocket(wrapper->client->net.fd, FIONBIO, &iMode);
|
129
128
|
#endif
|
130
|
-
}
|
131
129
|
|
132
|
-
/* It's safe to call mysql_close() on an already closed connection. */
|
133
|
-
if (!wrapper->closed) {
|
134
130
|
mysql_close(wrapper->client);
|
131
|
+
free(wrapper->client);
|
135
132
|
}
|
136
|
-
xfree(ptr);
|
137
|
-
}
|
138
133
|
|
139
|
-
static VALUE nogvl_close(void * ptr) {
|
140
|
-
mysql_client_wrapper *wrapper = ptr;
|
141
|
-
if (!wrapper->closed) {
|
142
|
-
mysql_close(wrapper->client);
|
143
|
-
wrapper->closed = 1;
|
144
|
-
}
|
145
134
|
return Qnil;
|
146
135
|
}
|
147
136
|
|
137
|
+
static void rb_mysql_client_free(void * ptr) {
|
138
|
+
mysql_client_wrapper *wrapper = (mysql_client_wrapper *)ptr;
|
139
|
+
|
140
|
+
nogvl_close(wrapper);
|
141
|
+
|
142
|
+
xfree(ptr);
|
143
|
+
}
|
144
|
+
|
148
145
|
static VALUE allocate(VALUE klass) {
|
149
146
|
VALUE obj;
|
150
147
|
mysql_client_wrapper * wrapper;
|
151
148
|
obj = Data_Make_Struct(klass, mysql_client_wrapper, rb_mysql_client_mark, rb_mysql_client_free, wrapper);
|
152
149
|
wrapper->encoding = Qnil;
|
153
150
|
wrapper->active = 0;
|
154
|
-
wrapper->closed =
|
151
|
+
wrapper->closed = 1;
|
152
|
+
wrapper->client = (MYSQL*)malloc(sizeof(MYSQL));
|
155
153
|
return obj;
|
156
154
|
}
|
157
155
|
|
@@ -166,7 +164,7 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
166
164
|
args.passwd = NIL_P(pass) ? NULL : StringValuePtr(pass);
|
167
165
|
args.db = NIL_P(database) ? NULL : StringValuePtr(database);
|
168
166
|
args.mysql = wrapper->client;
|
169
|
-
args.client_flag =
|
167
|
+
args.client_flag = NUM2ULONG(flags);
|
170
168
|
|
171
169
|
if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
|
172
170
|
// unable to connect
|
@@ -185,7 +183,9 @@ static VALUE rb_connect(VALUE self, VALUE user, VALUE pass, VALUE host, VALUE po
|
|
185
183
|
static VALUE rb_mysql_client_close(VALUE self) {
|
186
184
|
GET_CLIENT(self);
|
187
185
|
|
188
|
-
|
186
|
+
if (!wrapper->closed) {
|
187
|
+
rb_thread_blocking_region(nogvl_close, wrapper, RUBY_UBF_IO, 0);
|
188
|
+
}
|
189
189
|
|
190
190
|
return Qnil;
|
191
191
|
}
|
@@ -334,6 +334,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
|
334
334
|
unsigned long newLen, oldLen;
|
335
335
|
GET_CLIENT(self);
|
336
336
|
|
337
|
+
REQUIRE_OPEN_DB(wrapper);
|
337
338
|
Check_Type(str, T_STRING);
|
338
339
|
#ifdef HAVE_RUBY_ENCODING_H
|
339
340
|
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
@@ -345,7 +346,6 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
|
345
346
|
oldLen = RSTRING_LEN(str);
|
346
347
|
newStr = rb_str_new(0, oldLen*2+1);
|
347
348
|
|
348
|
-
REQUIRE_OPEN_DB(wrapper);
|
349
349
|
newLen = mysql_real_escape_string(wrapper->client, RSTRING_PTR(newStr), StringValuePtr(str), oldLen);
|
350
350
|
if (newLen == oldLen) {
|
351
351
|
// no need to return a new ruby string if nothing changed
|
@@ -365,6 +365,7 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
|
|
365
365
|
static VALUE rb_mysql_client_info(VALUE self) {
|
366
366
|
VALUE version = rb_hash_new(), client_info;
|
367
367
|
GET_CLIENT(self);
|
368
|
+
|
368
369
|
#ifdef HAVE_RUBY_ENCODING_H
|
369
370
|
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
370
371
|
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
@@ -385,13 +386,13 @@ static VALUE rb_mysql_client_info(VALUE self) {
|
|
385
386
|
static VALUE rb_mysql_client_server_info(VALUE self) {
|
386
387
|
VALUE version, server_info;
|
387
388
|
GET_CLIENT(self);
|
389
|
+
|
390
|
+
REQUIRE_OPEN_DB(wrapper);
|
388
391
|
#ifdef HAVE_RUBY_ENCODING_H
|
389
392
|
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
390
393
|
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
391
394
|
#endif
|
392
395
|
|
393
|
-
REQUIRE_OPEN_DB(wrapper);
|
394
|
-
|
395
396
|
version = rb_hash_new();
|
396
397
|
rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(wrapper->client)));
|
397
398
|
server_info = rb_str_new2(mysql_get_server_info(wrapper->client));
|
@@ -419,8 +420,14 @@ static VALUE rb_mysql_client_last_id(VALUE self) {
|
|
419
420
|
|
420
421
|
static VALUE rb_mysql_client_affected_rows(VALUE self) {
|
421
422
|
GET_CLIENT(self);
|
423
|
+
my_ulonglong retVal;
|
424
|
+
|
422
425
|
REQUIRE_OPEN_DB(wrapper);
|
423
|
-
|
426
|
+
retVal = mysql_affected_rows(wrapper->client);
|
427
|
+
if (retVal == (my_ulonglong)-1) {
|
428
|
+
rb_raise_mysql2_error(wrapper->client);
|
429
|
+
}
|
430
|
+
return ULL2NUM(retVal);
|
424
431
|
}
|
425
432
|
|
426
433
|
static VALUE set_reconnect(VALUE self, VALUE value) {
|
@@ -500,11 +507,12 @@ static VALUE set_ssl_options(VALUE self, VALUE key, VALUE cert, VALUE ca, VALUE
|
|
500
507
|
static VALUE init_connection(VALUE self) {
|
501
508
|
GET_CLIENT(self);
|
502
509
|
|
503
|
-
if (rb_thread_blocking_region(nogvl_init,
|
510
|
+
if (rb_thread_blocking_region(nogvl_init, wrapper->client, RUBY_UBF_IO, 0) == Qfalse) {
|
504
511
|
/* TODO: warning - not enough memory? */
|
505
512
|
return rb_raise_mysql2_error(wrapper->client);
|
506
513
|
}
|
507
514
|
|
515
|
+
wrapper->closed = 0;
|
508
516
|
return self;
|
509
517
|
}
|
510
518
|
|
data/ext/mysql2/extconf.rb
CHANGED
@@ -617,8 +617,15 @@ module ActiveRecord
|
|
617
617
|
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
618
618
|
variable_assignments = ['SQL_AUTO_IS_NULL=0']
|
619
619
|
encoding = @config[:encoding]
|
620
|
+
|
621
|
+
# make sure we set the encoding
|
620
622
|
variable_assignments << "NAMES '#{encoding}'" if encoding
|
621
623
|
|
624
|
+
# increase timeout so mysql server doesn't disconnect us
|
625
|
+
wait_timeout = @config[:wait_timeout]
|
626
|
+
wait_timeout = 2592000 unless wait_timeout.is_a?(Fixnum)
|
627
|
+
variable_assignments << "@@wait_timeout = #{wait_timeout}"
|
628
|
+
|
622
629
|
execute("SET #{variable_assignments.join(', ')}", :skip_logging)
|
623
630
|
end
|
624
631
|
|
data/lib/mysql2.rb
CHANGED
data/lib/mysql2/client.rb
CHANGED
@@ -8,7 +8,8 @@ module Mysql2
|
|
8
8
|
:symbolize_keys => false, # return field names as symbols instead of strings
|
9
9
|
:database_timezone => :local, # timezone Mysql2 will assume datetime objects are stored in
|
10
10
|
:application_timezone => nil, # timezone Mysql2 will convert to before handing the object back to the caller
|
11
|
-
:cache_rows => true
|
11
|
+
:cache_rows => true, # tells Mysql2 to use it's internal row cache for results
|
12
|
+
:connect_flags => REMEMBER_OPTIONS | LONG_PASSWORD | LONG_FLAG | TRANSACTIONS | PROTOCOL_41 | SECURE_CONNECTION
|
12
13
|
}
|
13
14
|
|
14
15
|
def initialize(opts = {})
|
@@ -31,7 +32,7 @@ module Mysql2
|
|
31
32
|
port = opts[:port] || 3306
|
32
33
|
database = opts[:database]
|
33
34
|
socket = opts[:socket]
|
34
|
-
flags = opts[:flags]
|
35
|
+
flags = opts[:flags] ? opts[:flags] | @query_options[:connect_flags] : @query_options[:connect_flags]
|
35
36
|
|
36
37
|
connect user, pass, host, port, database, socket, flags
|
37
38
|
end
|
data/lib/mysql2/em.rb
CHANGED
data/mysql2.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mysql2}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian Lopez"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-19}
|
13
13
|
s.email = %q{seniorlopez@gmail.com}
|
14
14
|
s.extensions = ["ext/mysql2/extconf.rb"]
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".gitignore",
|
20
|
+
".rspec",
|
20
21
|
"CHANGELOG.md",
|
21
22
|
"MIT-LICENSE",
|
22
23
|
"README.rdoc",
|
@@ -29,7 +30,6 @@ Gem::Specification.new do |s|
|
|
29
30
|
"benchmark/query_without_mysql_casting.rb",
|
30
31
|
"benchmark/sequel.rb",
|
31
32
|
"benchmark/setup_db.rb",
|
32
|
-
"benchmark/thread_alone.rb",
|
33
33
|
"examples/eventmachine.rb",
|
34
34
|
"examples/threaded.rb",
|
35
35
|
"ext/mysql2/client.c",
|
@@ -54,10 +54,11 @@ Gem::Specification.new do |s|
|
|
54
54
|
"spec/mysql2/error_spec.rb",
|
55
55
|
"spec/mysql2/result_spec.rb",
|
56
56
|
"spec/rcov.opts",
|
57
|
-
"spec/spec.opts",
|
58
57
|
"spec/spec_helper.rb",
|
59
58
|
"tasks/benchmarks.rake",
|
60
59
|
"tasks/compile.rake",
|
60
|
+
"tasks/jeweler.rake",
|
61
|
+
"tasks/rspec.rake",
|
61
62
|
"tasks/vendor_mysql.rake"
|
62
63
|
]
|
63
64
|
s.homepage = %q{http://github.com/brianmario/mysql2}
|
data/spec/em/em_spec.rb
CHANGED
@@ -1,26 +1,49 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
3
|
-
require '
|
2
|
+
if defined? EventMachine
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'mysql2/em'
|
4
5
|
|
5
|
-
describe Mysql2::EM::Client do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
describe Mysql2::EM::Client do
|
7
|
+
it "should support async queries" do
|
8
|
+
results = []
|
9
|
+
EM.run do
|
10
|
+
client1 = Mysql2::EM::Client.new
|
11
|
+
defer1 = client1.query "SELECT sleep(0.1) as first_query"
|
12
|
+
defer1.callback do |result|
|
13
|
+
results << result.first
|
14
|
+
EM.stop_event_loop
|
15
|
+
end
|
16
|
+
|
17
|
+
client2 = Mysql2::EM::Client.new
|
18
|
+
defer2 = client2.query "SELECT sleep(0.025) second_query"
|
19
|
+
defer2.callback do |result|
|
20
|
+
results << result.first
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
results[0].keys.should include("second_query")
|
25
|
+
results[1].keys.should include("first_query")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should support queries in callbacks" do
|
29
|
+
results = []
|
30
|
+
EM.run do
|
31
|
+
client = Mysql2::EM::Client.new
|
32
|
+
defer1 = client.query "SELECT sleep(0.025) as first_query"
|
33
|
+
defer1.callback do |result|
|
34
|
+
results << result.first
|
35
|
+
defer2 = client.query "SELECT sleep(0.025) as second_query"
|
36
|
+
defer2.callback do |result|
|
37
|
+
results << result.first
|
38
|
+
EM.stop_event_loop
|
39
|
+
end
|
40
|
+
end
|
20
41
|
end
|
42
|
+
|
43
|
+
results[0].keys.should include("first_query")
|
44
|
+
results[1].keys.should include("second_query")
|
21
45
|
end
|
22
|
-
|
23
|
-
results[0].keys.should include("second_query")
|
24
|
-
results[1].keys.should include("first_query")
|
25
46
|
end
|
26
|
-
|
47
|
+
else
|
48
|
+
puts "EventMachine not installed, skipping the specs that use it"
|
49
|
+
end
|
data/spec/mysql2/client_spec.rb
CHANGED
@@ -23,10 +23,10 @@ describe Mysql2::Client do
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
client = klient.new :flags => Mysql2::Client::FOUND_ROWS
|
26
|
-
client.connect_args.last.last
|
26
|
+
(client.connect_args.last.last & Mysql2::Client::FOUND_ROWS).should be_true
|
27
27
|
end
|
28
28
|
|
29
|
-
it "should default flags to
|
29
|
+
it "should default flags to (REMEMBER_OPTIONS, LONG_PASSWORD, LONG_FLAG, TRANSACTIONS, PROTOCOL_41, SECURE_CONNECTION)" do
|
30
30
|
klient = Class.new(Mysql2::Client) do
|
31
31
|
attr_reader :connect_args
|
32
32
|
def connect *args
|
@@ -35,7 +35,12 @@ describe Mysql2::Client do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
client = klient.new
|
38
|
-
client.connect_args.last.last
|
38
|
+
(client.connect_args.last.last & (Mysql2::Client::REMEMBER_OPTIONS |
|
39
|
+
Mysql2::Client::LONG_PASSWORD |
|
40
|
+
Mysql2::Client::LONG_FLAG |
|
41
|
+
Mysql2::Client::TRANSACTIONS |
|
42
|
+
Mysql2::Client::PROTOCOL_41 |
|
43
|
+
Mysql2::Client::SECURE_CONNECTION)).should be_true
|
39
44
|
end
|
40
45
|
|
41
46
|
it "should have a global default_query_options hash" do
|
@@ -71,6 +76,9 @@ describe Mysql2::Client do
|
|
71
76
|
|
72
77
|
it "should be able to close properly" do
|
73
78
|
@client.close.should be_nil
|
79
|
+
lambda {
|
80
|
+
@client.query "SELECT 1"
|
81
|
+
}.should raise_error(Mysql2::Error)
|
74
82
|
end
|
75
83
|
|
76
84
|
it "should respond to #query" do
|
@@ -103,6 +111,13 @@ describe Mysql2::Client do
|
|
103
111
|
}.should raise_error(Mysql2::Error)
|
104
112
|
end
|
105
113
|
|
114
|
+
it "should require an open connection" do
|
115
|
+
@client.close
|
116
|
+
lambda {
|
117
|
+
@client.query "SELECT 1"
|
118
|
+
}.should raise_error(Mysql2::Error)
|
119
|
+
end
|
120
|
+
|
106
121
|
# XXX this test is not deterministic (because Unix signal handling is not)
|
107
122
|
# and may fail on a loaded system
|
108
123
|
if RUBY_PLATFORM !~ /mingw|mswin/
|
@@ -137,25 +152,34 @@ describe Mysql2::Client do
|
|
137
152
|
@client.should respond_to(:escape)
|
138
153
|
end
|
139
154
|
|
140
|
-
|
141
|
-
|
142
|
-
|
155
|
+
context "#escape" do
|
156
|
+
it "should return a new SQL-escape version of the passed string" do
|
157
|
+
@client.escape("abc'def\"ghi\0jkl%mno").should eql("abc\\'def\\\"ghi\\0jkl%mno")
|
158
|
+
end
|
143
159
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
160
|
+
it "should return the passed string if nothing was escaped" do
|
161
|
+
str = "plain"
|
162
|
+
@client.escape(str).object_id.should eql(str.object_id)
|
163
|
+
end
|
148
164
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
165
|
+
it "should not overflow the thread stack" do
|
166
|
+
lambda {
|
167
|
+
Thread.new { @client.escape("'" * 256 * 1024) }.join
|
168
|
+
}.should_not raise_error(SystemStackError)
|
169
|
+
end
|
154
170
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
171
|
+
it "should not overflow the process stack" do
|
172
|
+
lambda {
|
173
|
+
Thread.new { @client.escape("'" * 1024 * 1024 * 4) }.join
|
174
|
+
}.should_not raise_error(SystemStackError)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should require an open connection" do
|
178
|
+
@client.close
|
179
|
+
lambda {
|
180
|
+
@client.escape ""
|
181
|
+
}.should raise_error(Mysql2::Error)
|
182
|
+
end
|
159
183
|
end
|
160
184
|
|
161
185
|
it "should respond to #info" do
|
@@ -203,6 +227,13 @@ describe Mysql2::Client do
|
|
203
227
|
server_info[:version].class.should eql(String)
|
204
228
|
end
|
205
229
|
|
230
|
+
it "#server_info should require an open connection" do
|
231
|
+
@client.close
|
232
|
+
lambda {
|
233
|
+
@client.server_info
|
234
|
+
}.should raise_error(Mysql2::Error)
|
235
|
+
end
|
236
|
+
|
206
237
|
if defined? Encoding
|
207
238
|
context "strings returned by #server_info" do
|
208
239
|
it "should default to the connection's encoding if Encoding.default_internal is nil" do
|
@@ -231,6 +262,13 @@ describe Mysql2::Client do
|
|
231
262
|
@client.socket.should_not eql(0)
|
232
263
|
end
|
233
264
|
|
265
|
+
it "#socket should require an open connection" do
|
266
|
+
@client.close
|
267
|
+
lambda {
|
268
|
+
@client.socket
|
269
|
+
}.should raise_error(Mysql2::Error)
|
270
|
+
end
|
271
|
+
|
234
272
|
it "should raise a Mysql2::Error exception upon connection failure" do
|
235
273
|
lambda {
|
236
274
|
bad_client = Mysql2::Client.new :host => "dfjhdi9wrhw", :username => 'asdfasdf8d2h'
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
require 'rspec'
|
4
5
|
require 'mysql2'
|
5
6
|
require 'timeout'
|
6
7
|
|
7
|
-
|
8
|
+
RSpec.configure do |config|
|
8
9
|
config.before(:all) do
|
9
10
|
client = Mysql2::Client.new :database => 'test'
|
10
11
|
client.query %[
|
data/tasks/compile.rake
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
gem 'rake-compiler', '~> 0.7.1'
|
2
2
|
require "rake/extensiontask"
|
3
3
|
|
4
|
-
MYSQL_VERSION = "5.1.
|
5
|
-
MYSQL_MIRROR = ENV['MYSQL_MIRROR'] || "http://mysql.
|
6
|
-
|
4
|
+
MYSQL_VERSION = "5.1.51"
|
5
|
+
MYSQL_MIRROR = ENV['MYSQL_MIRROR'] || "http://mysql.he.net/"
|
7
6
|
|
8
7
|
def gemspec
|
9
8
|
@clean_gemspec ||= eval(File.read(File.expand_path('../../mysql2.gemspec', __FILE__)))
|
@@ -13,15 +12,24 @@ Rake::ExtensionTask.new("mysql2", gemspec) do |ext|
|
|
13
12
|
# reference where the vendored MySQL got extracted
|
14
13
|
mysql_lib = File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', "mysql-#{MYSQL_VERSION}-win32"))
|
15
14
|
|
15
|
+
# DRY options feed into compile or cross-compile process
|
16
|
+
windows_options = [
|
17
|
+
"--with-mysql-include=#{mysql_lib}/include",
|
18
|
+
"--with-mysql-lib=#{mysql_lib}/lib/opt"
|
19
|
+
]
|
20
|
+
|
16
21
|
# automatically add build options to avoid need of manual input
|
17
22
|
if RUBY_PLATFORM =~ /mswin|mingw/ then
|
18
|
-
ext.config_options
|
19
|
-
ext.config_options << "--with-mysql-lib=#{mysql_lib}/lib/opt"
|
23
|
+
ext.config_options = windows_options
|
20
24
|
else
|
21
25
|
ext.cross_compile = true
|
22
26
|
ext.cross_platform = ['x86-mingw32', 'x86-mswin32-60']
|
23
|
-
ext.cross_config_options
|
24
|
-
|
27
|
+
ext.cross_config_options = windows_options
|
28
|
+
|
29
|
+
# inject 1.8/1.9 pure-ruby entry point when cross compiling only
|
30
|
+
ext.cross_compiling do |spec|
|
31
|
+
spec.files << 'lib/mysql2/mysql2.rb'
|
32
|
+
end
|
25
33
|
end
|
26
34
|
|
27
35
|
ext.lib_dir = File.join 'lib', 'mysql2'
|
@@ -30,3 +38,17 @@ Rake::ExtensionTask.new("mysql2", gemspec) do |ext|
|
|
30
38
|
CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
|
31
39
|
end
|
32
40
|
Rake::Task[:spec].prerequisites << :compile
|
41
|
+
|
42
|
+
file 'lib/mysql2/mysql2.rb' do |t|
|
43
|
+
name = gemspec.name
|
44
|
+
File.open(t.name, 'wb') do |f|
|
45
|
+
f.write <<-eoruby
|
46
|
+
RUBY_VERSION =~ /(\\d+.\\d+)/
|
47
|
+
require "#{name}/\#{$1}/#{name}"
|
48
|
+
eoruby
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if Rake::Task.task_defined?(:cross)
|
53
|
+
Rake::Task[:cross].prerequisites << "lib/mysql2/mysql2.rb"
|
54
|
+
end
|
data/tasks/jeweler.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
JEWELER = Jeweler::Tasks.new do |gem|
|
4
|
+
gem.name = "mysql2"
|
5
|
+
gem.summary = "A simple, fast Mysql library for Ruby, binding to libmysql"
|
6
|
+
gem.email = "seniorlopez@gmail.com"
|
7
|
+
gem.homepage = "http://github.com/brianmario/mysql2"
|
8
|
+
gem.authors = ["Brian Lopez"]
|
9
|
+
gem.require_paths = ["lib", "ext"]
|
10
|
+
gem.extra_rdoc_files = `git ls-files *.rdoc`.split("\n")
|
11
|
+
gem.files = `git ls-files`.split("\n")
|
12
|
+
gem.extensions = ["ext/mysql2/extconf.rb"]
|
13
|
+
gem.files.include %w(lib/jeweler/templates/.document lib/jeweler/templates/.gitignore)
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
puts "jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
desc "Run all examples with RCov"
|
6
|
+
RSpec::Core::RakeTask.new('spec:rcov') do |t|
|
7
|
+
t.rcov = true
|
8
|
+
end
|
9
|
+
RSpec::Core::RakeTask.new('spec') do |t|
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
rescue LoadError
|
15
|
+
puts "rspec, or one of its dependencies, is not available. Install it with: sudo gem install rspec"
|
16
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysql2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 29
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 5
|
10
|
+
version: 0.2.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian Lopez
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-10-19 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -29,6 +29,7 @@ extra_rdoc_files:
|
|
29
29
|
- README.rdoc
|
30
30
|
files:
|
31
31
|
- .gitignore
|
32
|
+
- .rspec
|
32
33
|
- CHANGELOG.md
|
33
34
|
- MIT-LICENSE
|
34
35
|
- README.rdoc
|
@@ -41,7 +42,6 @@ files:
|
|
41
42
|
- benchmark/query_without_mysql_casting.rb
|
42
43
|
- benchmark/sequel.rb
|
43
44
|
- benchmark/setup_db.rb
|
44
|
-
- benchmark/thread_alone.rb
|
45
45
|
- examples/eventmachine.rb
|
46
46
|
- examples/threaded.rb
|
47
47
|
- ext/mysql2/client.c
|
@@ -66,10 +66,11 @@ files:
|
|
66
66
|
- spec/mysql2/error_spec.rb
|
67
67
|
- spec/mysql2/result_spec.rb
|
68
68
|
- spec/rcov.opts
|
69
|
-
- spec/spec.opts
|
70
69
|
- spec/spec_helper.rb
|
71
70
|
- tasks/benchmarks.rake
|
72
71
|
- tasks/compile.rake
|
72
|
+
- tasks/jeweler.rake
|
73
|
+
- tasks/rspec.rake
|
73
74
|
- tasks/vendor_mysql.rake
|
74
75
|
has_rdoc: true
|
75
76
|
homepage: http://github.com/brianmario/mysql2
|
data/benchmark/thread_alone.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
require 'benchmark'
|
6
|
-
require 'mysql2'
|
7
|
-
|
8
|
-
iterations = 1000
|
9
|
-
client = Mysql2::Client.new(:host => "localhost", :username => "root", :database => "test")
|
10
|
-
query = lambda{ iterations.times{ client.query("SELECT mysql2_test.* FROM mysql2_test") } }
|
11
|
-
Benchmark.bmbm do |x|
|
12
|
-
x.report('select') do
|
13
|
-
query.call
|
14
|
-
end
|
15
|
-
x.report('rb_thread_select') do
|
16
|
-
thread = Thread.new{ sleep(10) }
|
17
|
-
query.call
|
18
|
-
thread.kill
|
19
|
-
end
|
20
|
-
end
|
data/spec/spec.opts
DELETED