mysql2 0.4.10 → 0.5.4

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.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +98 -38
  3. data/ext/mysql2/client.c +223 -76
  4. data/ext/mysql2/client.h +1 -39
  5. data/ext/mysql2/extconf.rb +46 -26
  6. data/ext/mysql2/mysql2_ext.c +8 -2
  7. data/ext/mysql2/mysql2_ext.h +8 -4
  8. data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -56
  9. data/ext/mysql2/mysql_enc_to_ruby.h +64 -3
  10. data/ext/mysql2/result.c +242 -86
  11. data/ext/mysql2/result.h +3 -3
  12. data/ext/mysql2/statement.c +90 -73
  13. data/ext/mysql2/statement.h +0 -2
  14. data/ext/mysql2/wait_for_single_fd.h +2 -1
  15. data/lib/mysql2/client.rb +51 -28
  16. data/lib/mysql2/em.rb +2 -4
  17. data/lib/mysql2/error.rb +52 -22
  18. data/lib/mysql2/result.rb +2 -0
  19. data/lib/mysql2/statement.rb +3 -11
  20. data/lib/mysql2/version.rb +1 -1
  21. data/lib/mysql2.rb +18 -15
  22. data/support/3A79BD29.asc +49 -0
  23. data/support/5072E1F5.asc +5 -5
  24. data/support/mysql_enc_to_ruby.rb +8 -3
  25. data/support/ruby_enc_to_mysql.rb +7 -5
  26. metadata +14 -58
  27. data/examples/eventmachine.rb +0 -21
  28. data/examples/threaded.rb +0 -18
  29. data/spec/configuration.yml.example +0 -11
  30. data/spec/em/em_spec.rb +0 -136
  31. data/spec/my.cnf.example +0 -9
  32. data/spec/mysql2/client_spec.rb +0 -1039
  33. data/spec/mysql2/error_spec.rb +0 -82
  34. data/spec/mysql2/result_spec.rb +0 -545
  35. data/spec/mysql2/statement_spec.rb +0 -776
  36. data/spec/rcov.opts +0 -3
  37. data/spec/spec_helper.rb +0 -108
  38. data/spec/ssl/ca-cert.pem +0 -17
  39. data/spec/ssl/ca-key.pem +0 -27
  40. data/spec/ssl/ca.cnf +0 -22
  41. data/spec/ssl/cert.cnf +0 -22
  42. data/spec/ssl/client-cert.pem +0 -17
  43. data/spec/ssl/client-key.pem +0 -27
  44. data/spec/ssl/client-req.pem +0 -15
  45. data/spec/ssl/gen_certs.sh +0 -48
  46. data/spec/ssl/pkcs8-client-key.pem +0 -28
  47. data/spec/ssl/pkcs8-server-key.pem +0 -28
  48. data/spec/ssl/server-cert.pem +0 -17
  49. data/spec/ssl/server-key.pem +0 -27
  50. data/spec/ssl/server-req.pem +0 -15
  51. data/spec/test_data +0 -1
data/ext/mysql2/result.c CHANGED
@@ -1,51 +1,34 @@
1
1
  #include <mysql2_ext.h>
2
2
 
3
3
  #include "mysql_enc_to_ruby.h"
4
+ #define MYSQL2_CHARSETNR_SIZE (sizeof(mysql2_mysql_enc_to_rb)/sizeof(mysql2_mysql_enc_to_rb[0]))
4
5
 
5
- #ifdef HAVE_RUBY_ENCODING_H
6
6
  static rb_encoding *binaryEncoding;
7
- #endif
8
7
 
9
- #if (SIZEOF_INT < SIZEOF_LONG) || defined(HAVE_RUBY_ENCODING_H)
10
8
  /* on 64bit platforms we can handle dates way outside 2038-01-19T03:14:07
11
9
  *
12
10
  * (9999*31557600) + (12*2592000) + (31*86400) + (11*3600) + (59*60) + 59
13
11
  */
14
12
  #define MYSQL2_MAX_TIME 315578267999ULL
15
- #else
16
- /**
17
- * On 32bit platforms the maximum date the Time class can handle is 2038-01-19T03:14:07
18
- * 2038 years + 1 month + 19 days + 3 hours + 14 minutes + 7 seconds = 64318634047 seconds
19
- *
20
- * (2038*31557600) + (1*2592000) + (19*86400) + (3*3600) + (14*60) + 7
21
- */
22
- #define MYSQL2_MAX_TIME 64318634047ULL
23
- #endif
24
13
 
25
- #if defined(HAVE_RUBY_ENCODING_H)
26
14
  /* 0000-1-1 00:00:00 UTC
27
15
  *
28
16
  * (0*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
29
17
  */
30
18
  #define MYSQL2_MIN_TIME 2678400ULL
31
- #elif SIZEOF_INT < SIZEOF_LONG /* 64bit Ruby 1.8 */
32
- /* 0139-1-1 00:00:00 UTC
33
- *
34
- * (139*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
35
- */
36
- #define MYSQL2_MIN_TIME 4389184800ULL
37
- #elif defined(NEGATIVE_TIME_T)
38
- /* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t.
39
- *
40
- * (1901*31557600) + (12*2592000) + (13*86400) + (20*3600) + (45*60) + 52
41
- */
42
- #define MYSQL2_MIN_TIME 60023299552ULL
43
- #else
44
- /* 1970-01-01 00:00:01 UTC : The Unix epoch - the oldest time in portable time_t.
45
- *
46
- * (1970*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 1
19
+
20
+ #define MYSQL2_MAX_BYTES_PER_CHAR 3
21
+
22
+ /* From Mysql documentations:
23
+ * To distinguish between binary and nonbinary data for string data types,
24
+ * check whether the charsetnr value is 63. If so, the character set is binary,
25
+ * which indicates binary rather than nonbinary data. This enables you to distinguish BINARY
26
+ * from CHAR, VARBINARY from VARCHAR, and the BLOB types from the TEXT types.
47
27
  */
48
- #define MYSQL2_MIN_TIME 62171150401ULL
28
+ #define MYSQL2_BINARY_CHARSET 63
29
+
30
+ #ifndef MYSQL_TYPE_JSON
31
+ #define MYSQL_TYPE_JSON 245
49
32
  #endif
50
33
 
51
34
  #define GET_RESULT(self) \
@@ -61,17 +44,18 @@ typedef struct {
61
44
  int streaming;
62
45
  ID db_timezone;
63
46
  ID app_timezone;
64
- VALUE block_given;
47
+ int block_given; /* boolean */
65
48
  } result_each_args;
66
49
 
67
- VALUE cBigDecimal, cDateTime, cDate;
68
- static VALUE cMysql2Result;
69
- static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
70
50
  extern VALUE mMysql2, cMysql2Client, cMysql2Error;
71
- static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
72
- static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_application_timezone,
73
- sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast, sym_stream, sym_name;
74
- static ID intern_merge;
51
+ static VALUE cMysql2Result, cDateTime, cDate;
52
+ static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
53
+ static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset,
54
+ intern_civil, intern_new_offset, intern_merge, intern_BigDecimal,
55
+ intern_query_options;
56
+ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
57
+ sym_application_timezone, sym_local, sym_utc, sym_cast_booleans,
58
+ sym_cache_rows, sym_cast, sym_stream, sym_name;
75
59
 
76
60
  /* Mark any VALUEs that are only referenced in C, so the GC won't get them. */
77
61
  static void rb_mysql_result_mark(void * wrapper) {
@@ -179,28 +163,25 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
179
163
  rb_field = rb_ary_entry(wrapper->fields, idx);
180
164
  if (rb_field == Qnil) {
181
165
  MYSQL_FIELD *field = NULL;
182
- #ifdef HAVE_RUBY_ENCODING_H
183
166
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
184
167
  rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
185
- #endif
186
168
 
187
169
  field = mysql_fetch_field_direct(wrapper->result, idx);
188
170
  if (symbolize_keys) {
189
- #ifdef HAVE_RB_INTERN3
190
171
  rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
191
172
  rb_field = ID2SYM(rb_field);
192
- #else
193
- VALUE colStr;
194
- colStr = rb_str_new(field->name, field->name_length);
195
- rb_field = ID2SYM(rb_to_id(colStr));
196
- #endif
197
173
  } else {
198
- rb_field = rb_str_new(field->name, field->name_length);
199
- #ifdef HAVE_RUBY_ENCODING_H
200
- rb_enc_associate(rb_field, conn_enc);
201
- if (default_internal_enc) {
174
+ #ifdef HAVE_RB_ENC_INTERNED_STR
175
+ rb_field = rb_enc_interned_str(field->name, field->name_length, conn_enc);
176
+ if (default_internal_enc && default_internal_enc != conn_enc) {
177
+ rb_field = rb_str_to_interned_str(rb_str_export_to_enc(rb_field, default_internal_enc));
178
+ }
179
+ #else
180
+ rb_field = rb_enc_str_new(field->name, field->name_length, conn_enc);
181
+ if (default_internal_enc && default_internal_enc != conn_enc) {
202
182
  rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
203
183
  }
184
+ rb_obj_freeze(rb_field);
204
185
  #endif
205
186
  }
206
187
  rb_ary_store(wrapper->fields, idx, rb_field);
@@ -209,10 +190,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
209
190
  return rb_field;
210
191
  }
211
192
 
212
- #ifdef HAVE_RUBY_ENCODING_H
193
+ static VALUE rb_mysql_result_fetch_field_type(VALUE self, unsigned int idx) {
194
+ VALUE rb_field_type;
195
+ GET_RESULT(self);
196
+
197
+ if (wrapper->fieldTypes == Qnil) {
198
+ wrapper->numberOfFields = mysql_num_fields(wrapper->result);
199
+ wrapper->fieldTypes = rb_ary_new2(wrapper->numberOfFields);
200
+ }
201
+
202
+ rb_field_type = rb_ary_entry(wrapper->fieldTypes, idx);
203
+ if (rb_field_type == Qnil) {
204
+ MYSQL_FIELD *field = NULL;
205
+ rb_encoding *default_internal_enc = rb_default_internal_encoding();
206
+ rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
207
+ int precision;
208
+
209
+ field = mysql_fetch_field_direct(wrapper->result, idx);
210
+
211
+ switch(field->type) {
212
+ case MYSQL_TYPE_NULL: // NULL
213
+ rb_field_type = rb_str_new_cstr("null");
214
+ break;
215
+ case MYSQL_TYPE_TINY: // signed char
216
+ rb_field_type = rb_sprintf("tinyint(%ld)", field->length);
217
+ break;
218
+ case MYSQL_TYPE_SHORT: // short int
219
+ rb_field_type = rb_sprintf("smallint(%ld)", field->length);
220
+ break;
221
+ case MYSQL_TYPE_YEAR: // short int
222
+ rb_field_type = rb_sprintf("year(%ld)", field->length);
223
+ break;
224
+ case MYSQL_TYPE_INT24: // int
225
+ rb_field_type = rb_sprintf("mediumint(%ld)", field->length);
226
+ break;
227
+ case MYSQL_TYPE_LONG: // int
228
+ rb_field_type = rb_sprintf("int(%ld)", field->length);
229
+ break;
230
+ case MYSQL_TYPE_LONGLONG: // long long int
231
+ rb_field_type = rb_sprintf("bigint(%ld)", field->length);
232
+ break;
233
+ case MYSQL_TYPE_FLOAT: // float
234
+ rb_field_type = rb_sprintf("float(%ld,%d)", field->length, field->decimals);
235
+ break;
236
+ case MYSQL_TYPE_DOUBLE: // double
237
+ rb_field_type = rb_sprintf("double(%ld,%d)", field->length, field->decimals);
238
+ break;
239
+ case MYSQL_TYPE_TIME: // MYSQL_TIME
240
+ rb_field_type = rb_str_new_cstr("time");
241
+ break;
242
+ case MYSQL_TYPE_DATE: // MYSQL_TIME
243
+ case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
244
+ rb_field_type = rb_str_new_cstr("date");
245
+ break;
246
+ case MYSQL_TYPE_DATETIME: // MYSQL_TIME
247
+ rb_field_type = rb_str_new_cstr("datetime");
248
+ break;
249
+ case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
250
+ rb_field_type = rb_str_new_cstr("timestamp");
251
+ break;
252
+ case MYSQL_TYPE_DECIMAL: // char[]
253
+ case MYSQL_TYPE_NEWDECIMAL: // char[]
254
+ /*
255
+ Handle precision similar to this line from mysql's code:
256
+ https://github.com/mysql/mysql-server/blob/ea7d2e2d16ac03afdd9cb72a972a95981107bf51/sql/field.cc#L2246
257
+ */
258
+ precision = field->length - (field->decimals > 0 ? 2 : 1);
259
+ rb_field_type = rb_sprintf("decimal(%d,%d)", precision, field->decimals);
260
+ break;
261
+ case MYSQL_TYPE_STRING: // char[]
262
+ if (field->flags & ENUM_FLAG) {
263
+ rb_field_type = rb_str_new_cstr("enum");
264
+ } else if (field->flags & SET_FLAG) {
265
+ rb_field_type = rb_str_new_cstr("set");
266
+ } else {
267
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
268
+ rb_field_type = rb_sprintf("binary(%ld)", field->length);
269
+ } else {
270
+ rb_field_type = rb_sprintf("char(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
271
+ }
272
+ }
273
+ break;
274
+ case MYSQL_TYPE_VAR_STRING: // char[]
275
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
276
+ rb_field_type = rb_sprintf("varbinary(%ld)", field->length);
277
+ } else {
278
+ rb_field_type = rb_sprintf("varchar(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
279
+ }
280
+ break;
281
+ case MYSQL_TYPE_VARCHAR: // char[]
282
+ rb_field_type = rb_sprintf("varchar(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
283
+ break;
284
+ case MYSQL_TYPE_TINY_BLOB: // char[]
285
+ rb_field_type = rb_str_new_cstr("tinyblob");
286
+ break;
287
+ case MYSQL_TYPE_BLOB: // char[]
288
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
289
+ switch(field->length) {
290
+ case 255:
291
+ rb_field_type = rb_str_new_cstr("tinyblob");
292
+ break;
293
+ case 65535:
294
+ rb_field_type = rb_str_new_cstr("blob");
295
+ break;
296
+ case 16777215:
297
+ rb_field_type = rb_str_new_cstr("mediumblob");
298
+ break;
299
+ case 4294967295:
300
+ rb_field_type = rb_str_new_cstr("longblob");
301
+ default:
302
+ break;
303
+ }
304
+ } else {
305
+ if (field->length == (255 * MYSQL2_MAX_BYTES_PER_CHAR)) {
306
+ rb_field_type = rb_str_new_cstr("tinytext");
307
+ } else if (field->length == (65535 * MYSQL2_MAX_BYTES_PER_CHAR)) {
308
+ rb_field_type = rb_str_new_cstr("text");
309
+ } else if (field->length == (16777215 * MYSQL2_MAX_BYTES_PER_CHAR)) {
310
+ rb_field_type = rb_str_new_cstr("mediumtext");
311
+ } else if (field->length == 4294967295) {
312
+ rb_field_type = rb_str_new_cstr("longtext");
313
+ } else {
314
+ rb_field_type = rb_sprintf("text(%ld)", field->length);
315
+ }
316
+ }
317
+ break;
318
+ case MYSQL_TYPE_MEDIUM_BLOB: // char[]
319
+ rb_field_type = rb_str_new_cstr("mediumblob");
320
+ break;
321
+ case MYSQL_TYPE_LONG_BLOB: // char[]
322
+ rb_field_type = rb_str_new_cstr("longblob");
323
+ break;
324
+ case MYSQL_TYPE_BIT: // char[]
325
+ rb_field_type = rb_sprintf("bit(%ld)", field->length);
326
+ break;
327
+ case MYSQL_TYPE_SET: // char[]
328
+ rb_field_type = rb_str_new_cstr("set");
329
+ break;
330
+ case MYSQL_TYPE_ENUM: // char[]
331
+ rb_field_type = rb_str_new_cstr("enum");
332
+ break;
333
+ case MYSQL_TYPE_GEOMETRY: // char[]
334
+ rb_field_type = rb_str_new_cstr("geometry");
335
+ break;
336
+ case MYSQL_TYPE_JSON: // json
337
+ rb_field_type = rb_str_new_cstr("json");
338
+ break;
339
+ default:
340
+ rb_field_type = rb_str_new_cstr("unknown");
341
+ break;
342
+ }
343
+
344
+ rb_enc_associate(rb_field_type, conn_enc);
345
+ if (default_internal_enc) {
346
+ rb_field_type = rb_str_export_to_enc(rb_field_type, default_internal_enc);
347
+ }
348
+
349
+ rb_ary_store(wrapper->fieldTypes, idx, rb_field_type);
350
+ }
351
+
352
+ return rb_field_type;
353
+ }
354
+
213
355
  static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
214
356
  /* if binary flag is set, respect its wishes */
215
- if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
357
+ if (field.flags & BINARY_FLAG && field.charsetnr == MYSQL2_BINARY_CHARSET) {
216
358
  rb_enc_associate(val, binaryEncoding);
217
359
  } else if (!field.charsetnr) {
218
360
  /* MySQL 4.x may not provide an encoding, binary will get the bytes through */
@@ -222,7 +364,8 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
222
364
  const char *enc_name;
223
365
  int enc_index;
224
366
 
225
- enc_name = mysql2_mysql_enc_to_rb[field.charsetnr-1];
367
+ enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
368
+
226
369
  if (enc_name != NULL) {
227
370
  /* use the field encoding we were able to match */
228
371
  enc_index = rb_enc_find_index(enc_name);
@@ -238,7 +381,6 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
238
381
  }
239
382
  return val;
240
383
  }
241
- #endif
242
384
 
243
385
  /* Interpret microseconds digits left-aligned in fixed-width field.
244
386
  * e.g. 10.123 seconds means 10 seconds and 123000 microseconds,
@@ -262,8 +404,8 @@ static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields
262
404
  if (wrapper->result_buffers != NULL) return;
263
405
 
264
406
  wrapper->result_buffers = xcalloc(wrapper->numberOfFields, sizeof(MYSQL_BIND));
265
- wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(bool));
266
- wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(bool));
407
+ wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
408
+ wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
267
409
  wrapper->length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
268
410
 
269
411
  for (i = 0; i < wrapper->numberOfFields; i++) {
@@ -278,12 +420,12 @@ static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields
278
420
  wrapper->result_buffers[i].buffer_length = sizeof(signed char);
279
421
  break;
280
422
  case MYSQL_TYPE_SHORT: // short int
423
+ case MYSQL_TYPE_YEAR: // short int
281
424
  wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(short int));
282
425
  wrapper->result_buffers[i].buffer_length = sizeof(short int);
283
426
  break;
284
427
  case MYSQL_TYPE_INT24: // int
285
428
  case MYSQL_TYPE_LONG: // int
286
- case MYSQL_TYPE_YEAR: // int
287
429
  wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(int));
288
430
  wrapper->result_buffers[i].buffer_length = sizeof(int);
289
431
  break;
@@ -335,16 +477,12 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
335
477
  VALUE rowVal;
336
478
  unsigned int i = 0;
337
479
 
338
- #ifdef HAVE_RUBY_ENCODING_H
339
480
  rb_encoding *default_internal_enc;
340
481
  rb_encoding *conn_enc;
341
- #endif
342
482
  GET_RESULT(self);
343
483
 
344
- #ifdef HAVE_RUBY_ENCODING_H
345
484
  default_internal_enc = rb_default_internal_encoding();
346
485
  conn_enc = rb_to_encoding(wrapper->encoding);
347
- #endif
348
486
 
349
487
  if (wrapper->fields == Qnil) {
350
488
  wrapper->numberOfFields = mysql_num_fields(wrapper->result);
@@ -413,6 +551,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
413
551
  }
414
552
  break;
415
553
  case MYSQL_TYPE_SHORT: // short int
554
+ case MYSQL_TYPE_YEAR: // short int
416
555
  if (result_buffer->is_unsigned) {
417
556
  val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
418
557
  } else {
@@ -421,7 +560,6 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
421
560
  break;
422
561
  case MYSQL_TYPE_INT24: // int
423
562
  case MYSQL_TYPE_LONG: // int
424
- case MYSQL_TYPE_YEAR: // int
425
563
  if (result_buffer->is_unsigned) {
426
564
  val = UINT2NUM(*((unsigned int*)result_buffer->buffer));
427
565
  } else {
@@ -492,7 +630,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
492
630
  }
493
631
  case MYSQL_TYPE_DECIMAL: // char[]
494
632
  case MYSQL_TYPE_NEWDECIMAL: // char[]
495
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
633
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
496
634
  break;
497
635
  case MYSQL_TYPE_STRING: // char[]
498
636
  case MYSQL_TYPE_VAR_STRING: // char[]
@@ -506,9 +644,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
506
644
  case MYSQL_TYPE_GEOMETRY: // char[]
507
645
  default:
508
646
  val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
509
- #ifdef HAVE_RUBY_ENCODING_H
510
647
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
511
- #endif
512
648
  break;
513
649
  }
514
650
  }
@@ -530,16 +666,12 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
530
666
  unsigned int i = 0;
531
667
  unsigned long * fieldLengths;
532
668
  void * ptr;
533
- #ifdef HAVE_RUBY_ENCODING_H
534
669
  rb_encoding *default_internal_enc;
535
670
  rb_encoding *conn_enc;
536
- #endif
537
671
  GET_RESULT(self);
538
672
 
539
- #ifdef HAVE_RUBY_ENCODING_H
540
673
  default_internal_enc = rb_default_internal_encoding();
541
674
  conn_enc = rb_to_encoding(wrapper->encoding);
542
- #endif
543
675
 
544
676
  ptr = wrapper->result;
545
677
  row = (MYSQL_ROW)rb_thread_call_without_gvl(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
@@ -569,9 +701,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
569
701
  val = Qnil;
570
702
  } else {
571
703
  val = rb_str_new(row[i], fieldLengths[i]);
572
- #ifdef HAVE_RUBY_ENCODING_H
573
704
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
574
- #endif
575
705
  }
576
706
  } else {
577
707
  switch(type) {
@@ -602,9 +732,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
602
732
  if (fields[i].decimals == 0) {
603
733
  val = rb_cstr2inum(row[i], 10);
604
734
  } else if (strtod(row[i], NULL) == 0.000000){
605
- val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
735
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, opt_decimal_zero);
606
736
  }else{
607
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
737
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(row[i], fieldLengths[i]));
608
738
  }
609
739
  break;
610
740
  case MYSQL_TYPE_FLOAT: /* FLOAT field */
@@ -722,9 +852,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
722
852
  case MYSQL_TYPE_GEOMETRY: /* Spatial fielda */
723
853
  default:
724
854
  val = rb_str_new(row[i], fieldLengths[i]);
725
- #ifdef HAVE_RUBY_ENCODING_H
726
855
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
727
- #endif
728
856
  break;
729
857
  }
730
858
  }
@@ -751,7 +879,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
751
879
 
752
880
  GET_RESULT(self);
753
881
 
754
- defaults = rb_iv_get(self, "@query_options");
882
+ defaults = rb_ivar_get(self, intern_query_options);
755
883
  Check_Type(defaults, T_HASH);
756
884
  if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
757
885
  symbolizeKeys = 1;
@@ -771,6 +899,25 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
771
899
  return wrapper->fields;
772
900
  }
773
901
 
902
+ static VALUE rb_mysql_result_fetch_field_types(VALUE self) {
903
+ unsigned int i = 0;
904
+
905
+ GET_RESULT(self);
906
+
907
+ if (wrapper->fieldTypes == Qnil) {
908
+ wrapper->numberOfFields = mysql_num_fields(wrapper->result);
909
+ wrapper->fieldTypes = rb_ary_new2(wrapper->numberOfFields);
910
+ }
911
+
912
+ if ((my_ulonglong)RARRAY_LEN(wrapper->fieldTypes) != wrapper->numberOfFields) {
913
+ for (i=0; i<wrapper->numberOfFields; i++) {
914
+ rb_mysql_result_fetch_field_type(self, i);
915
+ }
916
+ }
917
+
918
+ return wrapper->fieldTypes;
919
+ }
920
+
774
921
  static VALUE rb_mysql_result_each_(VALUE self,
775
922
  VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
776
923
  const result_each_args *args)
@@ -796,7 +943,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
796
943
  row = fetch_row_func(self, fields, args);
797
944
  if (row != Qnil) {
798
945
  wrapper->numberOfRows++;
799
- if (args->block_given != Qnil) {
946
+ if (args->block_given) {
800
947
  rb_yield(row);
801
948
  }
802
949
  }
@@ -846,7 +993,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
846
993
  return Qnil;
847
994
  }
848
995
 
849
- if (args->block_given != Qnil) {
996
+ if (args->block_given) {
850
997
  rb_yield(row);
851
998
  }
852
999
  }
@@ -864,7 +1011,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
864
1011
 
865
1012
  static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
866
1013
  result_each_args args;
867
- VALUE defaults, opts, block, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
1014
+ VALUE defaults, opts, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
868
1015
  ID db_timezone, app_timezone, dbTz, appTz;
869
1016
  int symbolizeKeys, asArray, castBool, cacheRows, cast;
870
1017
 
@@ -874,9 +1021,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
874
1021
  rb_raise(cMysql2Error, "Statement handle already closed");
875
1022
  }
876
1023
 
877
- defaults = rb_iv_get(self, "@query_options");
1024
+ defaults = rb_ivar_get(self, intern_query_options);
878
1025
  Check_Type(defaults, T_HASH);
879
- if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
1026
+
1027
+ // A block can be passed to this method, but since we don't call the block directly from C,
1028
+ // we don't need to capture it into a variable here with the "&" scan arg.
1029
+ if (rb_scan_args(argc, argv, "01", &opts) == 1) {
880
1030
  opts = rb_funcall(defaults, intern_merge, 1, opts);
881
1031
  } else {
882
1032
  opts = defaults;
@@ -942,7 +1092,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
942
1092
  args.cast = cast;
943
1093
  args.db_timezone = db_timezone;
944
1094
  args.app_timezone = app_timezone;
945
- args.block_given = block;
1095
+ args.block_given = rb_block_given_p();
946
1096
 
947
1097
  if (wrapper->stmt_wrapper) {
948
1098
  fetch_row_func = rb_mysql_result_fetch_row_stmt;
@@ -986,6 +1136,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
986
1136
  wrapper->resultFreed = 0;
987
1137
  wrapper->result = r;
988
1138
  wrapper->fields = Qnil;
1139
+ wrapper->fieldTypes = Qnil;
989
1140
  wrapper->rows = Qnil;
990
1141
  wrapper->encoding = encoding;
991
1142
  wrapper->streamingComplete = 0;
@@ -1007,7 +1158,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
1007
1158
  }
1008
1159
 
1009
1160
  rb_obj_call_init(obj, 0, NULL);
1010
- rb_iv_set(obj, "@query_options", options);
1161
+ rb_ivar_set(obj, intern_query_options, options);
1011
1162
 
1012
1163
  /* Options that cannot be changed in results.each(...) { |row| }
1013
1164
  * should be processed here. */
@@ -1017,13 +1168,18 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
1017
1168
  }
1018
1169
 
1019
1170
  void init_mysql2_result() {
1020
- cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
1021
1171
  cDate = rb_const_get(rb_cObject, rb_intern("Date"));
1172
+ rb_global_variable(&cDate);
1022
1173
  cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
1174
+ rb_global_variable(&cDateTime);
1023
1175
 
1024
1176
  cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
1177
+ rb_undef_alloc_func(cMysql2Result);
1178
+ rb_global_variable(&cMysql2Result);
1179
+
1025
1180
  rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
1026
1181
  rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
1182
+ rb_define_method(cMysql2Result, "field_types", rb_mysql_result_fetch_field_types, 0);
1027
1183
  rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0);
1028
1184
  rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
1029
1185
  rb_define_alias(cMysql2Result, "size", "count");
@@ -1036,6 +1192,8 @@ void init_mysql2_result() {
1036
1192
  intern_local_offset = rb_intern("local_offset");
1037
1193
  intern_civil = rb_intern("civil");
1038
1194
  intern_new_offset = rb_intern("new_offset");
1195
+ intern_BigDecimal = rb_intern("BigDecimal");
1196
+ intern_query_options = rb_intern("@query_options");
1039
1197
 
1040
1198
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
1041
1199
  sym_as = ID2SYM(rb_intern("as"));
@@ -1058,7 +1216,5 @@ void init_mysql2_result() {
1058
1216
  opt_time_month = INT2NUM(1);
1059
1217
  opt_utc_offset = INT2NUM(0);
1060
1218
 
1061
- #ifdef HAVE_RUBY_ENCODING_H
1062
1219
  binaryEncoding = rb_enc_find("binary");
1063
- #endif
1064
1220
  }
data/ext/mysql2/result.h CHANGED
@@ -1,12 +1,12 @@
1
1
  #ifndef MYSQL2_RESULT_H
2
2
  #define MYSQL2_RESULT_H
3
- #include <stdbool.h>
4
3
 
5
4
  void init_mysql2_result(void);
6
5
  VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r, VALUE statement);
7
6
 
8
7
  typedef struct {
9
8
  VALUE fields;
9
+ VALUE fieldTypes;
10
10
  VALUE rows;
11
11
  VALUE client;
12
12
  VALUE encoding;
@@ -22,8 +22,8 @@ typedef struct {
22
22
  mysql_client_wrapper *client_wrapper;
23
23
  /* statement result bind buffers */
24
24
  MYSQL_BIND *result_buffers;
25
- bool *is_null;
26
- bool *error;
25
+ my_bool *is_null;
26
+ my_bool *error;
27
27
  unsigned long *length;
28
28
  } mysql2_result_wrapper;
29
29