do_mysql 0.9.11 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/LICENSE +1 -1
  2. data/Manifest.txt +15 -4
  3. data/Rakefile +7 -122
  4. data/ext/do_mysql_ext/do_mysql_ext.c +154 -99
  5. data/ext/do_mysql_ext/extconf.rb +1 -0
  6. data/lib/do_mysql.rb +5 -2
  7. data/lib/do_mysql/version.rb +1 -1
  8. data/spec/command_spec.rb +9 -0
  9. data/spec/connection_spec.rb +19 -0
  10. data/spec/encoding_spec.rb +8 -0
  11. data/spec/lib/rspec_immediate_feedback_formatter.rb +3 -0
  12. data/spec/reader_spec.rb +8 -0
  13. data/spec/result_spec.rb +9 -0
  14. data/spec/spec_helper.rb +38 -47
  15. data/spec/typecast/array_spec.rb +8 -0
  16. data/spec/typecast/bigdecimal_spec.rb +9 -0
  17. data/spec/typecast/boolean_spec.rb +9 -0
  18. data/spec/typecast/byte_array_spec.rb +8 -0
  19. data/spec/typecast/class_spec.rb +8 -0
  20. data/spec/typecast/date_spec.rb +9 -0
  21. data/spec/typecast/datetime_spec.rb +9 -0
  22. data/spec/typecast/float_spec.rb +9 -0
  23. data/spec/typecast/integer_spec.rb +8 -0
  24. data/spec/typecast/nil_spec.rb +10 -0
  25. data/spec/typecast/range_spec.rb +8 -0
  26. data/spec/typecast/string_spec.rb +8 -0
  27. data/spec/typecast/time_spec.rb +8 -0
  28. data/tasks/gem.rake +60 -0
  29. data/tasks/install.rake +15 -0
  30. data/tasks/native.rake +31 -0
  31. data/tasks/release.rake +75 -0
  32. data/tasks/retrieve.rake +67 -0
  33. data/tasks/spec.rake +18 -0
  34. metadata +72 -40
  35. data/.gitignore +0 -0
  36. data/buildfile +0 -27
  37. data/ext-java/src/main/java/DoMysqlExtService.java +0 -23
  38. data/ext-java/src/main/java/do_mysql/MySqlDriverDefinition.java +0 -22
  39. data/ext/.gitignore +0 -2
  40. data/spec/integration/do_mysql_spec.rb +0 -341
  41. data/spec/integration/logging_spec.rb +0 -52
  42. data/spec/integration/quoting_spec.rb +0 -45
  43. data/spec/spec.opts +0 -2
  44. data/spec/unit/transaction_spec.rb +0 -35
data/LICENSE CHANGED
@@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
17
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -13,9 +13,20 @@ ext/do_mysql_ext/extconf.rb
13
13
  lib/do_mysql.rb
14
14
  lib/do_mysql/transaction.rb
15
15
  lib/do_mysql/version.rb
16
- spec/integration/do_mysql_spec.rb
17
- spec/integration/logging_spec.rb
18
- spec/integration/quoting_spec.rb
16
+ spec/command_spec.rb
17
+ spec/connection_spec.rb
18
+ spec/reader_spec.rb
19
+ spec/result_spec.rb
19
20
  spec/spec.opts
20
21
  spec/spec_helper.rb
21
- spec/unit/transaction_spec.rb
22
+ spec/typecast/bigdecimal_spec.rb
23
+ spec/typecast/boolean_spec.rb
24
+ spec/typecast/byte_array_spec.rb
25
+ spec/typecast/class_spec.rb
26
+ spec/typecast/date_spec.rb
27
+ spec/typecast/datetime_spec.rb
28
+ spec/typecast/float_spec.rb
29
+ spec/typecast/integer_spec.rb
30
+ spec/typecast/nil_spec.rb
31
+ spec/typecast/string_spec.rb
32
+ spec/typecast/time_spec.rb
data/Rakefile CHANGED
@@ -1,131 +1,16 @@
1
- require 'pathname'
2
1
  require 'rubygems'
3
- require 'spec/rake/spectask'
4
- require 'lib/do_mysql/version'
2
+ require 'rake'
3
+ require 'rake/clean'
5
4
 
5
+ require 'pathname'
6
+ require 'lib/do_mysql/version'
6
7
 
7
8
  ROOT = Pathname(__FILE__).dirname.expand_path
8
9
  JRUBY = RUBY_PLATFORM =~ /java/
9
10
  WINDOWS = Gem.win_platform?
10
11
  SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
12
+ BINARY_VERSION = '5.0.77'
11
13
 
12
- AUTHOR = "Dirkjan Bussink"
13
- EMAIL = "d.bussink@gmail.com"
14
- GEM_NAME = "do_mysql"
15
- GEM_VERSION = DataObjects::Mysql::VERSION
16
- GEM_DEPENDENCIES = if JRUBY
17
- [["data_objects", GEM_VERSION], ["do_jdbc", GEM_VERSION], ["jdbc-mysql", ">=5.0.4"]]
18
- else
19
- [["data_objects", GEM_VERSION]]
20
- end
21
- GEM_CLEAN = ['**/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,lib,def,exp,DS_Store}',
22
- 'ext/Makefile', 'ext-java/target']
23
- GEM_EXTRAS = if JRUBY
24
- {
25
- :has_rdoc => false,
26
- :platform => 'java'
27
- }
28
- else
29
- {
30
- :has_rdoc => false,
31
- :extensions => 'ext/do_mysql_ext/extconf.rb'
32
- }
33
- end
34
-
35
- PROJECT_NAME = "dorb"
36
- PROJECT_URL = "http://rubyforge.org/projects/dorb"
37
- PROJECT_DESCRIPTION = PROJECT_SUMMARY = "A DataObject.rb driver for MySQL"
38
-
39
-
40
- # RCov is run by default, except on the JRuby platform, or if NO_RCOV env is true
41
- RUN_RCOV = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
42
-
43
- if (tasks_dir = ROOT.parent + 'tasks').directory?
44
- require tasks_dir + 'hoe'
45
- require tasks_dir + 'ext_helper_java'
46
-
47
- setup_java_extension "#{GEM_NAME}_ext", HOE.spec
48
- end
49
-
50
- if JRUBY
51
- HOE.spec.files += ['lib/do_mysql_ext.jar']
52
- HOE.spec.require_paths = Dir['lib']
53
- end
54
-
55
- # compile the extension
56
- if JRUBY
57
- Rake::Task['compile:jruby'].invoke
58
- else
59
- begin
60
- gem('rake-compiler')
61
- require 'rake/extensiontask'
62
- Rake::ExtensionTask.new('do_mysql_ext', HOE.spec)
63
- rescue LoadError
64
- warn "To cross-compile, install rake-compiler (gem install rake-compiler)"
65
- if tasks_dir.directory?
66
- require tasks_dir + 'ext_helper'
67
- setup_c_extension('do_mysql_ext', HOE.spec)
68
- end
69
- end
70
- end
71
-
72
- def sudo_gem(cmd)
73
- sh "#{SUDO} #{RUBY} -S gem #{cmd}", :verbose => false
74
- end
75
-
76
- # Installation
77
-
78
- desc "Install #{GEM_NAME} #{GEM_VERSION}"
79
- task :install => [ :package ] do
80
- sudo_gem "install pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
81
- end
82
-
83
- desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
84
- task :uninstall => [ :clobber ] do
85
- sudo_gem "uninstall #{GEM_NAME} -v#{GEM_VERSION} -I -x"
86
- end
87
-
88
- # Specs
89
-
90
- desc 'Run specifications'
91
- Spec::Rake::SpecTask.new(:spec) do |t|
92
- t.spec_opts << '--format' << 'specdoc' << '--colour'
93
- t.spec_opts << '--loadby' << 'random'
94
- t.spec_files = Pathname.glob(ENV['FILES'] || 'spec/**/*_spec.rb').map { |f| f.to_s }
95
-
96
- begin
97
- t.rcov = RUN_RCOV
98
- t.rcov_opts << '--exclude' << 'spec'
99
- t.rcov_opts << '--text-summary'
100
- t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
101
- rescue Exception
102
- # rcov not installed
103
- end
104
- end
105
-
106
- namespace :ci do
107
-
108
- task :prepare do
109
- rm_rf ROOT + "ci"
110
- mkdir_p ROOT + "ci"
111
- mkdir_p ROOT + "ci/doc"
112
- mkdir_p ROOT + "ci/cyclomatic"
113
- mkdir_p ROOT + "ci/token"
114
- end
115
-
116
- task :publish do
117
- out = ENV['CC_BUILD_ARTIFACTS'] || "out"
118
- mkdir_p out unless File.directory? out
119
-
120
- mv "ci/rspec_report.html", "#{out}/rspec_report.html"
121
- mv "ci/coverage", "#{out}/coverage"
122
- end
123
-
124
- task :spec => :prepare do
125
- Rake::Task[:spec].invoke
126
- mv ROOT + "coverage", ROOT + "ci/coverage"
127
- end
128
-
129
- end
14
+ Dir['tasks/*.rake'].each { |f| import f }
130
15
 
131
- task :ci => ["ci:spec"]
16
+ CLEAN.include(%w[ {tmp,pkg}/ **/*.{o,so,bundle,jar,log,a,gem,dSYM,obj,pdb,exp,DS_Store,rbc,db} ext/do_mysql_ext/Makefile ext-java/target ])
@@ -3,7 +3,6 @@
3
3
  #include <math.h>
4
4
  #include <ctype.h>
5
5
  #include <time.h>
6
- #include <my_global.h>
7
6
  #include <mysql.h>
8
7
  #include <errmsg.h>
9
8
  #include <mysqld_error.h>
@@ -29,8 +28,10 @@
29
28
  #endif
30
29
 
31
30
  #ifdef _WIN32
31
+ #define cCommand_execute cCommand_execute_sync
32
32
  #define do_int64 signed __int64
33
33
  #else
34
+ #define cCommand_execute cCommand_execute_async
34
35
  #define do_int64 signed long long int
35
36
  #endif
36
37
 
@@ -40,7 +41,6 @@ static ID ID_TO_F;
40
41
  static ID ID_TO_S;
41
42
  static ID ID_TO_TIME;
42
43
  static ID ID_NEW;
43
- static ID ID_NEW_RATIONAL;
44
44
  static ID ID_NEW_DATE;
45
45
  static ID ID_CONST_GET;
46
46
  static ID ID_RATIONAL;
@@ -51,6 +51,9 @@ static ID ID_LOGGER;
51
51
  static ID ID_DEBUG;
52
52
  static ID ID_LEVEL;
53
53
 
54
+ // Reference to Extlib module
55
+ static VALUE mExtlib;
56
+
54
57
  // References to DataObjects base classes
55
58
  static VALUE mDO;
56
59
  static VALUE cDO_Quoting;
@@ -63,6 +66,7 @@ static VALUE cDO_Reader;
63
66
  static VALUE rb_cDate;
64
67
  static VALUE rb_cDateTime;
65
68
  static VALUE rb_cBigDecimal;
69
+ static VALUE rb_cByteArray;
66
70
 
67
71
  // Classes that we'll build in Init
68
72
  static VALUE mDOMysql;
@@ -71,61 +75,44 @@ static VALUE cCommand;
71
75
  static VALUE cResult;
72
76
  static VALUE cReader;
73
77
  static VALUE eMysqlError;
78
+ static VALUE eArgumentError;
74
79
 
75
80
  // Figures out what we should cast a given mysql field type to
76
81
  static VALUE infer_ruby_type(MYSQL_FIELD *field) {
77
-
78
- char* ruby_type;
79
-
80
82
  switch(field->type) {
81
- case MYSQL_TYPE_NULL: {
82
- ruby_type = NULL;
83
- break;
84
- }
85
- case MYSQL_TYPE_TINY: {
86
- ruby_type = "TrueClass";
87
- break;
88
- }
83
+ case MYSQL_TYPE_NULL:
84
+ return Qnil;
85
+ case MYSQL_TYPE_TINY:
86
+ return rb_cTrueClass;
89
87
  case MYSQL_TYPE_BIT:
90
88
  case MYSQL_TYPE_SHORT:
91
89
  case MYSQL_TYPE_LONG:
92
90
  case MYSQL_TYPE_INT24:
93
91
  case MYSQL_TYPE_LONGLONG:
94
- case MYSQL_TYPE_YEAR: {
95
- ruby_type = "Fixnum";
96
- break;
97
- }
92
+ case MYSQL_TYPE_YEAR:
93
+ return rb_cInteger;
94
+ case MYSQL_TYPE_NEWDECIMAL:
98
95
  case MYSQL_TYPE_DECIMAL:
99
- case MYSQL_TYPE_NEWDECIMAL: {
100
- ruby_type = "BigDecimal";
101
- break;
102
- }
96
+ return rb_cBigDecimal;
103
97
  case MYSQL_TYPE_FLOAT:
104
- case MYSQL_TYPE_DOUBLE: {
105
- ruby_type = "Float";
106
- break;
107
- }
98
+ case MYSQL_TYPE_DOUBLE:
99
+ return rb_cFloat;
108
100
  case MYSQL_TYPE_TIMESTAMP:
109
- case MYSQL_TYPE_DATETIME: {
110
- ruby_type = "DateTime";
111
- break;
112
- }
113
- case MYSQL_TYPE_TIME: {
114
- ruby_type = "DateTime";
115
- break;
116
- }
101
+ case MYSQL_TYPE_DATETIME:
102
+ return rb_cDateTime;
103
+ case MYSQL_TYPE_TIME:
104
+ return rb_cDateTime;
117
105
  case MYSQL_TYPE_DATE:
118
- case MYSQL_TYPE_NEWDATE: {
119
- ruby_type = "Date";
120
- break;
121
- }
122
- default: {
123
- ruby_type = "String";
124
- break;
125
- }
106
+ case MYSQL_TYPE_NEWDATE:
107
+ return rb_cDate;
108
+ case MYSQL_TYPE_TINY_BLOB:
109
+ case MYSQL_TYPE_MEDIUM_BLOB:
110
+ case MYSQL_TYPE_LONG_BLOB:
111
+ case MYSQL_TYPE_BLOB:
112
+ return rb_cByteArray;
113
+ default:
114
+ return rb_cString;
126
115
  }
127
-
128
- return rb_str_new2(ruby_type);
129
116
  }
130
117
 
131
118
  // Find the greatest common denominator and reduce the provided numerator and denominator.
@@ -185,7 +172,7 @@ static VALUE parse_date(const char *date) {
185
172
 
186
173
  static VALUE parse_time(const char *date) {
187
174
 
188
- int year, month, day, hour, min, sec, usec;
175
+ int year, month, day, hour, min, sec, usec, tokens;
189
176
  char subsec[7];
190
177
 
191
178
  if (0 != strchr(date, '.')) {
@@ -193,7 +180,12 @@ static VALUE parse_time(const char *date) {
193
180
  sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d.%s", &year, &month, &day, &hour, &min, &sec, subsec);
194
181
  sscanf(subsec, "%d", &usec);
195
182
  } else {
196
- sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
183
+ tokens = sscanf(date, "%4d-%2d-%2d %2d:%2d:%2d", &year, &month, &day, &hour, &min, &sec);
184
+ if (tokens == 3) {
185
+ hour = 0;
186
+ min = 0;
187
+ sec = 0;
188
+ }
197
189
  usec = 0;
198
190
  }
199
191
 
@@ -240,9 +232,14 @@ static VALUE parse_date_time(const char *date) {
240
232
  } else if ((max_tokens - 1) == tokens_read) {
241
233
  // We read the Date and Time, but no Minute Offset
242
234
  minute_offset = 0;
243
- } else if (tokens_read == 3) {
244
- return parse_date(date);
245
- } else if (tokens_read >= (max_tokens - 3)) {
235
+ } else if (tokens_read == 3 || tokens_read >= (max_tokens - 3)) {
236
+ if (tokens_read == 3) {
237
+ hour = 0;
238
+ min = 0;
239
+ hour_offset = 0;
240
+ minute_offset = 0;
241
+ sec = 0;
242
+ }
246
243
  // We read the Date and Time, default to the current locale's offset
247
244
 
248
245
  // Get localtime
@@ -298,31 +295,40 @@ static VALUE parse_date_time(const char *date) {
298
295
  }
299
296
 
300
297
  // Convert C-string to a Ruby instance of Ruby type "type"
301
- static VALUE typecast(const char* value, unsigned long length, const char* type) {
302
- if (NULL == value)
298
+ static VALUE typecast(const char *value, long length, const VALUE type) {
299
+
300
+ if(NULL == value) {
303
301
  return Qnil;
302
+ }
304
303
 
305
- if ( strcmp(type, "Class") == 0) {
306
- return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
307
- } else if ( strcmp(type, "Integer") == 0 || strcmp(type, "Fixnum") == 0 || strcmp(type, "Bignum") == 0 ) {
304
+ if (type == rb_cInteger) {
308
305
  return rb_cstr2inum(value, 10);
309
- } else if (0 == strcmp("String", type)) {
306
+ } else if (type == rb_cString) {
310
307
  return TAINTED_STRING(value, length);
311
- } else if (0 == strcmp("Float", type) ) {
308
+ } else if (type == rb_cFloat) {
312
309
  return rb_float_new(rb_cstr_to_dbl(value, Qfalse));
313
- } else if (0 == strcmp("BigDecimal", type) ) {
310
+ } else if (type == rb_cBigDecimal) {
314
311
  return rb_funcall(rb_cBigDecimal, ID_NEW, 1, TAINTED_STRING(value, length));
315
- } else if (0 == strcmp("TrueClass", type) || 0 == strcmp("FalseClass", type)) {
316
- return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
317
- } else if (0 == strcmp("Date", type)) {
312
+ } else if (type == rb_cDate) {
318
313
  return parse_date(value);
319
- } else if (0 == strcmp("DateTime", type)) {
314
+ } else if (type == rb_cDateTime) {
320
315
  return parse_date_time(value);
321
- } else if (0 == strcmp("Time", type)) {
316
+ } else if (type == rb_cTime) {
322
317
  return parse_time(value);
318
+ } else if (type == rb_cTrueClass) {
319
+ return (0 == value || 0 == strcmp("0", value)) ? Qfalse : Qtrue;
320
+ } else if (type == rb_cByteArray) {
321
+ return rb_funcall(rb_cByteArray, ID_NEW, 1, TAINTED_STRING(value, length));
322
+ } else if (type == rb_cClass) {
323
+ return rb_funcall(rb_cObject, rb_intern("full_const_get"), 1, TAINTED_STRING(value, length));
324
+ } else if (type == rb_cObject) {
325
+ return rb_marshal_load(rb_str_new(value, length));
326
+ } else if (type == rb_cNilClass) {
327
+ return Qnil;
323
328
  } else {
324
329
  return TAINTED_STRING(value, length);
325
330
  }
331
+
326
332
  }
327
333
 
328
334
  static void data_objects_debug(VALUE string, struct timeval* start) {
@@ -341,9 +347,6 @@ static void data_objects_debug(VALUE string, struct timeval* start) {
341
347
  gettimeofday(&stop, NULL);
342
348
 
343
349
  duration = (stop.tv_sec - start->tv_sec) * 1000000 + stop.tv_usec - start->tv_usec;
344
- if(stop.tv_usec < start->tv_usec) {
345
- duration += 1000000;
346
- }
347
350
 
348
351
  snprintf(total_time, 32, "%.6f", duration / 1000000.0);
349
352
  message = (char *)calloc(length + strlen(total_time) + 4, sizeof(char));
@@ -379,6 +382,29 @@ static char * get_uri_option(VALUE query_hash, char * key) {
379
382
  return value;
380
383
  }
381
384
 
385
+ #ifdef _WIN32
386
+ static MYSQL_RES* cCommand_execute_sync(VALUE self, MYSQL* db, VALUE query) {
387
+ int retval;
388
+ struct timeval start;
389
+ char* str = RSTRING_PTR(query);
390
+ int len = RSTRING_LEN(query);
391
+
392
+ VALUE connection = rb_iv_get(self, "@connection");
393
+
394
+ if(mysql_ping(db) && mysql_errno(db) == CR_SERVER_GONE_ERROR) {
395
+ CHECK_AND_RAISE(mysql_errno(db), "Mysql server has gone away. \
396
+ Please report this issue to the Datamapper project. \
397
+ Specify your at least your MySQL version when filing a ticket");
398
+ }
399
+ gettimeofday(&start, NULL);
400
+ retval = mysql_real_query(db, str, len);
401
+ CHECK_AND_RAISE(retval, str);
402
+
403
+ data_objects_debug(query, &start);
404
+
405
+ return mysql_store_result(db);
406
+ }
407
+ #else
382
408
  static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
383
409
  int socket_fd;
384
410
  int retval;
@@ -427,6 +453,7 @@ static MYSQL_RES* cCommand_execute_async(VALUE self, MYSQL* db, VALUE query) {
427
453
 
428
454
  return mysql_store_result(db);
429
455
  }
456
+ #endif
430
457
 
431
458
  static VALUE cConnection_initialize(VALUE self, VALUE uri) {
432
459
  VALUE r_host, r_user, r_password, r_path, r_query, r_port;
@@ -508,8 +535,10 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
508
535
  raise_mysql_error(Qnil, db, -1, NULL);
509
536
  }
510
537
 
538
+ #ifdef MYSQL_OPT_RECONNECT
511
539
  my_bool reconnect = 1;
512
540
  mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect);
541
+ #endif
513
542
 
514
543
  // Set the connections character set
515
544
  encoding_error = mysql_set_character_set(db, encoding);
@@ -518,8 +547,8 @@ static VALUE cConnection_initialize(VALUE self, VALUE uri) {
518
547
  }
519
548
 
520
549
  // Disable sql_auto_is_null
521
- cCommand_execute_async(self, db, rb_str_new2("SET sql_auto_is_null = 0"));
522
- cCommand_execute_async(self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_AUTO_VALUE_ON_ZERO,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
550
+ cCommand_execute(self, db, rb_str_new2("SET sql_auto_is_null = 0"));
551
+ cCommand_execute(self, db, rb_str_new2("SET SESSION sql_mode = 'ANSI,NO_AUTO_VALUE_ON_ZERO,NO_DIR_IN_CREATE,NO_ENGINE_SUBSTITUTION,NO_UNSIGNED_SUBTRACTION,TRADITIONAL'"));
523
552
 
524
553
  rb_iv_set(self, "@uri", uri);
525
554
  rb_iv_set(self, "@connection", Data_Wrap_Struct(rb_cObject, 0, 0, db));
@@ -570,12 +599,32 @@ static VALUE cConnection_dispose(VALUE self) {
570
599
  Accepts an array of Ruby types (Fixnum, Float, String, etc...) and turns them
571
600
  into Ruby-strings so we can easily typecast later
572
601
  */
573
- static VALUE cCommand_set_types(VALUE self, VALUE array) {
602
+ static VALUE cCommand_set_types(int argc, VALUE *argv, VALUE self) {
574
603
  VALUE type_strings = rb_ary_new();
575
- int i;
604
+ VALUE array = rb_ary_new();
605
+
606
+ int i, j;
607
+
608
+ for ( i = 0; i < argc; i++) {
609
+ rb_ary_push(array, argv[i]);
610
+ }
576
611
 
577
612
  for (i = 0; i < RARRAY_LEN(array); i++) {
578
- rb_ary_push(type_strings, RUBY_STRING(rb_class2name(rb_ary_entry(array, i))));
613
+ VALUE entry = rb_ary_entry(array, i);
614
+ if(TYPE(entry) == T_CLASS) {
615
+ rb_ary_push(type_strings, entry);
616
+ } else if (TYPE(entry) == T_ARRAY) {
617
+ for (j = 0; j < RARRAY_LEN(entry); j++) {
618
+ VALUE sub_entry = rb_ary_entry(entry, j);
619
+ if(TYPE(sub_entry) == T_CLASS) {
620
+ rb_ary_push(type_strings, sub_entry);
621
+ } else {
622
+ rb_raise(eArgumentError, "Invalid type given");
623
+ }
624
+ }
625
+ } else {
626
+ rb_raise(eArgumentError, "Invalid type given");
627
+ }
579
628
  }
580
629
 
581
630
  rb_iv_set(self, "@field_types", type_strings);
@@ -583,23 +632,23 @@ static VALUE cCommand_set_types(VALUE self, VALUE array) {
583
632
  return array;
584
633
  }
585
634
 
586
- VALUE cCommand_quote_time(VALUE self, VALUE value) {
635
+ VALUE cConnection_quote_time(VALUE self, VALUE value) {
587
636
  return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
588
637
  }
589
638
 
590
639
 
591
- VALUE cCommand_quote_date_time(VALUE self, VALUE value) {
640
+ VALUE cConnection_quote_date_time(VALUE self, VALUE value) {
592
641
  // TODO: Support non-local dates. we need to call #new_offset on the date to be
593
642
  // quoted and pass in the current locale's date offset (self.new_offset((hours * 3600).to_r / 86400)
594
643
  return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d %H:%M:%S'"));
595
644
  }
596
645
 
597
- VALUE cCommand_quote_date(VALUE self, VALUE value) {
646
+ VALUE cConnection_quote_date(VALUE self, VALUE value) {
598
647
  return rb_funcall(value, ID_STRFTIME, 1, RUBY_STRING("'%Y-%m-%d'"));
599
648
  }
600
649
 
601
- static VALUE cCommand_quote_string(VALUE self, VALUE string) {
602
- MYSQL *db = DATA_PTR(rb_iv_get(rb_iv_get(self, "@connection"), "@connection"));
650
+ static VALUE cConnection_quote_string(VALUE self, VALUE string) {
651
+ MYSQL *db = DATA_PTR(rb_iv_get(self, "@connection"));
603
652
  const char *source = RSTRING_PTR(string);
604
653
  int source_len = RSTRING_LEN(string);
605
654
  char *escaped;
@@ -624,14 +673,14 @@ static VALUE cCommand_quote_string(VALUE self, VALUE string) {
624
673
 
625
674
  static VALUE build_query_from_args(VALUE klass, int count, VALUE *args) {
626
675
  VALUE query = rb_iv_get(klass, "@text");
627
- if ( count > 0 ) {
628
- int i;
629
- VALUE array = rb_ary_new();
630
- for ( i = 0; i < count; i++) {
631
- rb_ary_push(array, (VALUE)args[i]);
632
- }
633
- query = rb_funcall(klass, ID_ESCAPE_SQL, 1, array);
676
+
677
+ int i;
678
+ VALUE array = rb_ary_new();
679
+ for ( i = 0; i < count; i++) {
680
+ rb_ary_push(array, (VALUE)args[i]);
634
681
  }
682
+ query = rb_funcall(klass, ID_ESCAPE_SQL, 1, array);
683
+
635
684
  return query;
636
685
  }
637
686
 
@@ -643,13 +692,14 @@ static VALUE cCommand_execute_non_query(int argc, VALUE *argv, VALUE self) {
643
692
  my_ulonglong affected_rows;
644
693
  VALUE connection = rb_iv_get(self, "@connection");
645
694
  VALUE mysql_connection = rb_iv_get(connection, "@connection");
646
- if (Qnil == mysql_connection)
695
+ if (Qnil == mysql_connection) {
647
696
  rb_raise(eMysqlError, "This connection has already been closed.");
697
+ }
648
698
 
649
699
  MYSQL *db = DATA_PTR(mysql_connection);
650
700
  query = build_query_from_args(self, argc, argv);
651
701
 
652
- response = cCommand_execute_async(self, db, query);
702
+ response = cCommand_execute(self, db, query);
653
703
 
654
704
  affected_rows = mysql_affected_rows(db);
655
705
  mysql_free_result(response);
@@ -681,7 +731,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
681
731
 
682
732
  query = build_query_from_args(self, argc, argv);
683
733
 
684
- response = cCommand_execute_async(self, db, query);
734
+ response = cCommand_execute(self, db, query);
685
735
 
686
736
  if (!response) {
687
737
  return Qnil;
@@ -704,7 +754,7 @@ static VALUE cCommand_execute_reader(int argc, VALUE *argv, VALUE self) {
704
754
  // Whoops... wrong number of types passed to set_types. Close the reader and raise
705
755
  // and error
706
756
  rb_funcall(reader, rb_intern("close"), 0);
707
- rb_raise(eMysqlError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
757
+ rb_raise(eArgumentError, "Field-count mismatch. Expected %ld fields, but the query yielded %d", RARRAY_LEN(field_types), field_count);
708
758
  }
709
759
 
710
760
  for(i = 0; i < field_count; i++) {
@@ -753,34 +803,35 @@ static VALUE cReader_close(VALUE self) {
753
803
  static VALUE cReader_next(VALUE self) {
754
804
  // Get the reader from the instance variable, maybe refactor this?
755
805
  VALUE reader_container = rb_iv_get(self, "@reader");
756
- VALUE ruby_field_type_strings, row;
806
+ VALUE field_types, field_type, row;
757
807
 
758
808
  MYSQL_RES *reader;
759
809
  MYSQL_ROW result;
760
810
  unsigned long *lengths;
761
811
 
762
812
  int i;
763
- const char *field_type;
764
813
 
765
- if (Qnil == reader_container)
814
+ if (Qnil == reader_container) {
766
815
  return Qfalse;
816
+ }
767
817
 
768
818
  reader = DATA_PTR(reader_container);
769
819
 
770
820
  // The Meat
771
- ruby_field_type_strings = rb_iv_get(self, "@field_types");
821
+ field_types = rb_iv_get(self, "@field_types");
772
822
  row = rb_ary_new();
773
- result = (MYSQL_ROW)mysql_fetch_row(reader);
823
+ result = mysql_fetch_row(reader);
774
824
  lengths = mysql_fetch_lengths(reader);
775
825
 
776
826
  rb_iv_set(self, "@state", result ? Qtrue : Qfalse);
777
827
 
778
- if (!result)
779
- return Qnil;
828
+ if (!result) {
829
+ return Qfalse;
830
+ }
780
831
 
781
832
  for (i = 0; i < reader->field_count; i++) {
782
833
  // The field_type data could be cached in a c-array
783
- field_type = RSTRING_PTR(rb_ary_entry(ruby_field_type_strings, i));
834
+ field_type = rb_ary_entry(field_types, i);
784
835
  rb_ary_push(row, typecast(result[i], lengths[i], field_type));
785
836
  }
786
837
 
@@ -841,6 +892,10 @@ void Init_do_mysql_ext() {
841
892
  rb_cDateTime = RUBY_CLASS("DateTime");
842
893
  rb_cBigDecimal = RUBY_CLASS("BigDecimal");
843
894
 
895
+ // Get references to the Extlib module
896
+ mExtlib = CONST_GET(rb_mKernel, "Extlib");
897
+ rb_cByteArray = CONST_GET(mExtlib, "ByteArray");
898
+
844
899
  // Get references to the DataObjects module and its classes
845
900
  mDO = CONST_GET(rb_mKernel, "DataObjects");
846
901
  cDO_Quoting = CONST_GET(mDO, "Quoting");
@@ -852,6 +907,7 @@ void Init_do_mysql_ext() {
852
907
  // Top Level Module that all the classes live under
853
908
  mDOMysql = rb_define_module_under(mDO, "Mysql");
854
909
 
910
+ eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
855
911
  eMysqlError = rb_define_class("MysqlError", rb_eStandardError);
856
912
 
857
913
  cConnection = DRIVER_CLASS("Connection", cDO_Connection);
@@ -859,16 +915,15 @@ void Init_do_mysql_ext() {
859
915
  rb_define_method(cConnection, "using_socket?", cConnection_is_using_socket, 0);
860
916
  rb_define_method(cConnection, "character_set", cConnection_character_set , 0);
861
917
  rb_define_method(cConnection, "dispose", cConnection_dispose, 0);
918
+ rb_define_method(cConnection, "quote_string", cConnection_quote_string, 1);
919
+ rb_define_method(cConnection, "quote_date", cConnection_quote_date, 1);
920
+ rb_define_method(cConnection, "quote_time", cConnection_quote_time, 1);
921
+ rb_define_method(cConnection, "quote_datetime", cConnection_quote_date_time, 1);
862
922
 
863
923
  cCommand = DRIVER_CLASS("Command", cDO_Command);
864
- rb_include_module(cCommand, cDO_Quoting);
865
- rb_define_method(cCommand, "set_types", cCommand_set_types, 1);
924
+ rb_define_method(cCommand, "set_types", cCommand_set_types, -1);
866
925
  rb_define_method(cCommand, "execute_non_query", cCommand_execute_non_query, -1);
867
926
  rb_define_method(cCommand, "execute_reader", cCommand_execute_reader, -1);
868
- rb_define_method(cCommand, "quote_string", cCommand_quote_string, 1);
869
- rb_define_method(cCommand, "quote_date", cCommand_quote_date, 1);
870
- rb_define_method(cCommand, "quote_time", cCommand_quote_time, 1);
871
- rb_define_method(cCommand, "quote_datetime", cCommand_quote_date_time, 1);
872
927
 
873
928
  // Non-Query result
874
929
  cResult = DRIVER_CLASS("Result", cDO_Result);