mysql2 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.6 (May 14th, 2010)
4
+ * more fixes to the AR adapter related to casting
5
+ * add missing index creation override method to AR adapter
6
+ * added sql_state and error_number methods to the Mysql2::Error exception class
7
+
3
8
  ## 0.1.5 (May 12th, 2010)
4
9
  * quite a few patches from Eric Wong related to thread-safety, non-blocking I/O and general cleanup
5
10
  ** wrap mysql_real_connect with rb_thread_blocking_region
@@ -109,7 +109,7 @@ The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
109
109
  * ree-1.8.7-2010.01
110
110
  * 1.9.1-p378
111
111
  * ruby-trunk
112
- * rbx-head
112
+ * rbx-head - broken at the moment, working with the rbx team for a solution
113
113
 
114
114
  The ActiveRecord driver should work on 2.3.5 and 3.0
115
115
 
@@ -137,4 +137,8 @@ then iterating over every row using an #each like method yielding a block:
137
137
  Mysql
138
138
  7.330000 0.350000 7.680000 ( 8.013160)
139
139
  do_mysql
140
- 1.740000 0.220000 1.960000 ( 2.909290)
140
+ 1.740000 0.220000 1.960000 ( 2.909290)
141
+
142
+ == Special Thanks
143
+
144
+ * Eric Wong - for the contribution (and informative explanations of) of some thread-safety, non-blocking I/O and cleanup patches. You rock dude
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
@@ -140,8 +140,7 @@ static VALUE rb_mysql_client_new(int argc, VALUE * argv, VALUE klass) {
140
140
 
141
141
  if (rb_thread_blocking_region(nogvl_init, &args, RUBY_UBF_IO, 0) == Qfalse) {
142
142
  // TODO: warning - not enough memory?
143
- rb_raise(cMysql2Error, "%s", mysql_error(args.mysql));
144
- return Qnil;
143
+ return rb_raise_mysql2_error(args.mysql);
145
144
  }
146
145
 
147
146
  // set default reconnect behavior
@@ -168,8 +167,7 @@ static VALUE rb_mysql_client_new(int argc, VALUE * argv, VALUE klass) {
168
167
 
169
168
  if (rb_thread_blocking_region(nogvl_connect, &args, RUBY_UBF_IO, 0) == Qfalse) {
170
169
  // unable to connect
171
- rb_raise(cMysql2Error, "%s", mysql_error(args.mysql));
172
- return Qnil;
170
+ return rb_raise_mysql2_error(args.mysql);;
173
171
  }
174
172
 
175
173
  client->client = args.mysql;
@@ -268,10 +266,13 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
268
266
  Check_Type(args.sql, T_STRING);
269
267
 
270
268
  GetMysql2Client(self, args.mysql);
271
- if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
272
- rb_raise(cMysql2Error, "%s", mysql_error(args.mysql));
269
+ if (!args.mysql) {
270
+ rb_raise(cMysql2Error, "closed MySQL connection");
273
271
  return Qnil;
274
272
  }
273
+ if (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
274
+ return rb_raise_mysql2_error(args.mysql);;
275
+ }
275
276
 
276
277
  if (!async) {
277
278
  // the below code is largely from do_mysql
@@ -308,7 +309,10 @@ static VALUE rb_mysql_client_escape(VALUE self, VALUE str) {
308
309
  char escaped[(oldLen*2)+1];
309
310
 
310
311
  GetMysql2Client(self, client);
311
-
312
+ if (!client) {
313
+ rb_raise(cMysql2Error, "closed MySQL connection");
314
+ return Qnil;
315
+ }
312
316
  newLen = mysql_real_escape_string(client, escaped, RSTRING_PTR(str), RSTRING_LEN(str));
313
317
  if (newLen == oldLen) {
314
318
  // no need to return a new ruby string if nothing changed
@@ -334,6 +338,10 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
334
338
  VALUE version;
335
339
 
336
340
  GetMysql2Client(self, client);
341
+ if (!client) {
342
+ rb_raise(cMysql2Error, "closed MySQL connection");
343
+ return Qnil;
344
+ }
337
345
  version = rb_hash_new();
338
346
  rb_hash_aset(version, sym_id, LONG2FIX(mysql_get_server_version(client)));
339
347
  rb_hash_aset(version, sym_version, rb_str_new2(mysql_get_server_info(client)));
@@ -341,7 +349,11 @@ static VALUE rb_mysql_client_server_info(VALUE self) {
341
349
  }
342
350
 
343
351
  static VALUE rb_mysql_client_socket(VALUE self) {
344
- MYSQL * client = GetMysql2Client(self, client);;
352
+ MYSQL * client = GetMysql2Client(self, client);
353
+ if (!client) {
354
+ rb_raise(cMysql2Error, "closed MySQL connection");
355
+ return Qnil;
356
+ }
345
357
  return INT2NUM(client->net.fd);
346
358
  }
347
359
 
@@ -369,16 +381,18 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
369
381
  MYSQL * client;
370
382
  MYSQL_RES * result;
371
383
  GetMysql2Client(self, client);
372
-
373
- if (rb_thread_blocking_region(nogvl_read_query_result, client, RUBY_UBF_IO, 0) == Qfalse) {
374
- rb_raise(cMysql2Error, "%s", mysql_error(client));
384
+ if (!client) {
385
+ rb_raise(cMysql2Error, "closed MySQL connection");
375
386
  return Qnil;
376
387
  }
388
+ if (rb_thread_blocking_region(nogvl_read_query_result, client, RUBY_UBF_IO, 0) == Qfalse) {
389
+ return rb_raise_mysql2_error(client);
390
+ }
377
391
 
378
392
  result = (MYSQL_RES *)rb_thread_blocking_region(nogvl_store_result, client, RUBY_UBF_IO, 0);
379
393
  if (result == NULL) {
380
394
  if (mysql_field_count(client) != 0) {
381
- rb_raise(cMysql2Error, "%s", mysql_error(client));
395
+ rb_raise_mysql2_error(client);
382
396
  }
383
397
  return Qnil;
384
398
  }
@@ -389,14 +403,20 @@ static VALUE rb_mysql_client_async_result(VALUE self) {
389
403
  static VALUE rb_mysql_client_last_id(VALUE self) {
390
404
  MYSQL * client;
391
405
  GetMysql2Client(self, client);
392
-
406
+ if (!client) {
407
+ rb_raise(cMysql2Error, "closed MySQL connection");
408
+ return Qnil;
409
+ }
393
410
  return ULL2NUM(mysql_insert_id(client));
394
411
  }
395
412
 
396
413
  static VALUE rb_mysql_client_affected_rows(VALUE self) {
397
414
  MYSQL * client;
398
415
  GetMysql2Client(self, client);
399
-
416
+ if (!client) {
417
+ rb_raise(cMysql2Error, "closed MySQL connection");
418
+ return Qnil;
419
+ }
400
420
  return ULL2NUM(mysql_affected_rows(client));
401
421
  }
402
422
 
@@ -542,6 +562,7 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
542
562
  } else {
543
563
  if (month < 1 || day < 1) {
544
564
  rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
565
+ val = Qnil;
545
566
  } else {
546
567
  val = rb_funcall(rb_cTime, intern_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
547
568
  }
@@ -557,6 +578,7 @@ static VALUE rb_mysql_result_fetch_row(int argc, VALUE * argv, VALUE self) {
557
578
  } else {
558
579
  if (month < 1 || day < 1) {
559
580
  rb_raise(cMysql2Error, "Invalid date: %s", row[i]);
581
+ val = Qnil;
560
582
  } else {
561
583
  val = rb_funcall(cDate, intern_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
562
584
  }
@@ -648,6 +670,22 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
648
670
  return wrapper->rows;
649
671
  }
650
672
 
673
+ static VALUE rb_mysql_error_error_number(VALUE obj) {
674
+ return rb_iv_get(obj, "error_number");
675
+ }
676
+
677
+ static VALUE rb_mysql_error_sql_state(VALUE obj) {
678
+ return rb_iv_get(obj, "sql_state");
679
+ }
680
+
681
+ static VALUE rb_raise_mysql2_error(MYSQL *client) {
682
+ VALUE e = rb_exc_new2(cMysql2Error, mysql_error(client));
683
+ rb_iv_set(e, "error_number", INT2FIX(mysql_errno(client)));
684
+ rb_iv_set(e, "sql_state", rb_tainted_str_new2(mysql_sqlstate(client)));
685
+ rb_exc_raise(e);
686
+ return Qnil;
687
+ }
688
+
651
689
  /* Ruby Extension initializer */
652
690
  void Init_mysql2_ext() {
653
691
  rb_require("date");
@@ -673,6 +711,8 @@ void Init_mysql2_ext() {
673
711
  rb_define_method(cMysql2Client, "affected_rows", rb_mysql_client_affected_rows, 0);
674
712
 
675
713
  cMysql2Error = rb_define_class_under(mMysql2, "Error", rb_eStandardError);
714
+ rb_define_method(cMysql2Error, "error_number", rb_mysql_error_error_number, 0);
715
+ rb_define_method(cMysql2Error, "sql_state", rb_mysql_error_sql_state, 0);
676
716
 
677
717
  cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
678
718
  rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
@@ -70,6 +70,11 @@ static void rb_mysql_result_free(void * wrapper);
70
70
  static void rb_mysql_result_mark(void * wrapper);
71
71
  static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper);
72
72
 
73
+ /* Mysql2::Error */
74
+ static VALUE rb_raise_mysql2_error(MYSQL *client);
75
+ static VALUE rb_mysql_error_error_number(VALUE obj);
76
+ static VALUE rb_mysql_error_sql_state(VALUE obj);
77
+
73
78
  /*
74
79
  * used to pass all arguments to mysql_real_connect while inside
75
80
  * rb_thread_blocking_region
@@ -52,26 +52,33 @@ module ActiveRecord
52
52
  def type_cast(value)
53
53
  return nil if value.nil?
54
54
  case type
55
- when :string then value
56
- when :text then value
57
- when :integer then value.is_a?(Fixnum) ? value : (value.to_i rescue value ? 1 : 0)
58
- when :float then value.class == Float ? value : value.to_f
59
- when :decimal then value.class == BigDecimal ? value : self.class.value_to_decimal(value)
60
- when :datetime then value.class == Time ? value : self.class.string_to_time(value)
61
- when :timestamp then value.class == Time ? value : self.class.string_to_time(value)
62
- when :time then value.class == Time ? value : self.class.string_to_dummy_time(value)
63
- when :date then value.class == Date ? value : self.class.string_to_date(value)
64
- when :binary then value
65
- when :boolean then self.class.value_to_boolean(value)
55
+ when :string then value
56
+ when :text then value
57
+ when :integer then value.to_i rescue value ? 1 : 0
58
+ when :float then value.to_f # returns self if it's already a Float
59
+ when :decimal then self.class.value_to_decimal(value)
60
+ when :datetime, :timestamp then value.class == Time ? value : self.class.string_to_time(value)
61
+ when :time then value.class == Time ? value : self.class.string_to_dummy_time(value)
62
+ when :date then value.class == Date ? value : self.class.string_to_date(value)
63
+ when :binary then value
64
+ when :boolean then self.class.value_to_boolean(value)
66
65
  else value
67
66
  end
68
67
  end
69
68
 
70
69
  def type_cast_code(var_name)
71
70
  case type
72
- when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
73
- else
74
- nil
71
+ when :string then nil
72
+ when :text then nil
73
+ when :integer then "#{var_name}.to_i rescue #{var_name} ? 1 : 0"
74
+ when :float then "#{var_name}.to_f"
75
+ when :decimal then "#{self.class.name}.value_to_decimal(#{var_name})"
76
+ when :datetime, :timestamp then "#{var_name}.class == Time ? #{var_name} : #{self.class.name}.string_to_time(#{var_name})"
77
+ when :time then "#{var_name}.class == Time ? #{var_name} : #{self.class.name}.string_to_dummy_time(#{var_name})"
78
+ when :date then "#{var_name}.class == Date ? #{var_name} : #{self.class.name}.string_to_date(#{var_name})"
79
+ when :binary then nil
80
+ when :boolean then "#{self.class.name}.value_to_boolean(#{var_name})"
81
+ else nil
75
82
  end
76
83
  end
77
84
 
@@ -234,10 +241,11 @@ module ActiveRecord
234
241
  end
235
242
 
236
243
  def disconnect!
237
- @connection = nil
244
+ @connection.close
238
245
  end
239
246
 
240
247
  def reset!
248
+ disconnect!
241
249
  @connection = Mysql2::Client.new(@config)
242
250
  end
243
251
 
@@ -523,6 +531,19 @@ module ActiveRecord
523
531
  end
524
532
 
525
533
  protected
534
+ def quoted_columns_for_index(column_names, options = {})
535
+ length = options[:length] if options.is_a?(Hash)
536
+
537
+ quoted_column_names = case length
538
+ when Hash
539
+ column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) }
540
+ when Fixnum
541
+ column_names.map {|name| "#{quote_column_name(name)}(#{length})"}
542
+ else
543
+ column_names.map {|name| quote_column_name(name) }
544
+ end
545
+ end
546
+
526
547
  # TODO: implement error_number method on Mysql2::Exception
527
548
  def translate_exception(exception, message)
528
549
  return super unless exception.respond_to?(:error_number)
@@ -5,5 +5,5 @@ require 'mysql2_ext'
5
5
  #
6
6
  # A modern, simple and very fast Mysql library for Ruby - binding to libmysql
7
7
  module Mysql2
8
- VERSION = "0.1.5"
8
+ VERSION = "0.1.6"
9
9
  end
@@ -150,12 +150,12 @@ module Sequel
150
150
 
151
151
  # Closes given database connection.
152
152
  def disconnect_connection(c)
153
- c = nil
153
+ c.close
154
154
  end
155
155
 
156
156
  # Convert tinyint(1) type to boolean if convert_tinyint_to_bool is true
157
157
  def schema_column_type(db_type)
158
- Sequel::MySQL.convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
158
+ Sequel::Mysql2.convert_tinyint_to_bool && db_type == 'tinyint(1)' ? :boolean : super
159
159
  end
160
160
  end
161
161
 
@@ -204,12 +204,12 @@ module Sequel
204
204
 
205
205
  # Insert a new value into this dataset
206
206
  def insert(*values)
207
- execute_dui(insert_sql(*values)){|c| return c.insert_id}
207
+ execute_dui(insert_sql(*values)){|c| return c.last_id}
208
208
  end
209
209
 
210
210
  # Replace (update or insert) the matching row.
211
211
  def replace(*args)
212
- execute_dui(replace_sql(*args)){|c| return c.insert_id}
212
+ execute_dui(replace_sql(*args)){|c| return c.last_id}
213
213
  end
214
214
 
215
215
  # Update the matching rows.
@@ -229,9 +229,9 @@ module Sequel
229
229
  super(sql, {:type=>:dui}.merge(opts), &block)
230
230
  end
231
231
 
232
- # Handle correct quoting of strings using ::MySQL.quote.
232
+ # Handle correct quoting of strings using ::Mysql2#escape.
233
233
  def literal_string(v)
234
- db.synchronize{|c| "'#{c.quote(v)}'"}
234
+ db.synchronize{|c| "'#{c.escape(v)}'"}
235
235
  end
236
236
  end
237
237
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mysql2}
8
- s.version = "0.1.5"
8
+ s.version = "0.1.6"
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-05-12}
12
+ s.date = %q{2010-05-14}
13
13
  s.email = %q{seniorlopez@gmail.com}
14
14
  s.extensions = ["ext/extconf.rb"]
15
15
  s.extra_rdoc_files = [
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
41
41
  "spec/active_record/active_record_spec.rb",
42
42
  "spec/em/em_spec.rb",
43
43
  "spec/mysql2/client_spec.rb",
44
+ "spec/mysql2/error_spec.rb",
44
45
  "spec/mysql2/result_spec.rb",
45
46
  "spec/rcov.opts",
46
47
  "spec/spec.opts",
@@ -55,6 +56,7 @@ Gem::Specification.new do |s|
55
56
  "spec/active_record/active_record_spec.rb",
56
57
  "spec/em/em_spec.rb",
57
58
  "spec/mysql2/client_spec.rb",
59
+ "spec/mysql2/error_spec.rb",
58
60
  "spec/mysql2/result_spec.rb",
59
61
  "spec/spec_helper.rb",
60
62
  "examples/eventmachine.rb"
@@ -6,11 +6,6 @@ describe Mysql2::Client do
6
6
  @client = Mysql2::Client.new
7
7
  end
8
8
 
9
- after(:each) do
10
- # forcefully clean up old connections
11
- GC.start
12
- end
13
-
14
9
  it "should be able to connect via SSL options" do
15
10
  pending("DON'T WORRY, THIS TEST PASSES :) - but is machine-specific. You need to have MySQL running with SSL configured and enabled. Then update the paths in this test to your needs and remove the pending state.")
16
11
  ssl_client = nil
@@ -0,0 +1,16 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+
4
+ describe Mysql2::Error do
5
+ before(:each) do
6
+ @error = Mysql2::Error.new "testing"
7
+ end
8
+
9
+ it "should respond to #error_number" do
10
+ @error.should respond_to(:error_number)
11
+ end
12
+
13
+ it "should respond to #sql_state" do
14
+ @error.should respond_to(:sql_state)
15
+ end
16
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 5
9
- version: 0.1.5
8
+ - 6
9
+ version: 0.1.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Lopez
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-12 00:00:00 -07:00
17
+ date: 2010-05-14 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -52,6 +52,7 @@ files:
52
52
  - spec/active_record/active_record_spec.rb
53
53
  - spec/em/em_spec.rb
54
54
  - spec/mysql2/client_spec.rb
55
+ - spec/mysql2/error_spec.rb
55
56
  - spec/mysql2/result_spec.rb
56
57
  - spec/rcov.opts
57
58
  - spec/spec.opts
@@ -91,6 +92,7 @@ test_files:
91
92
  - spec/active_record/active_record_spec.rb
92
93
  - spec/em/em_spec.rb
93
94
  - spec/mysql2/client_spec.rb
95
+ - spec/mysql2/error_spec.rb
94
96
  - spec/mysql2/result_spec.rb
95
97
  - spec/spec_helper.rb
96
98
  - examples/eventmachine.rb