mysql2 0.4.10 → 0.5.6

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 (52) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +167 -48
  3. data/ext/mysql2/client.c +335 -108
  4. data/ext/mysql2/client.h +10 -41
  5. data/ext/mysql2/extconf.rb +84 -26
  6. data/ext/mysql2/mysql2_ext.c +8 -2
  7. data/ext/mysql2/mysql2_ext.h +21 -4
  8. data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -55
  9. data/ext/mysql2/mysql_enc_to_ruby.h +79 -3
  10. data/ext/mysql2/result.c +298 -92
  11. data/ext/mysql2/result.h +3 -3
  12. data/ext/mysql2/statement.c +137 -81
  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 +55 -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 +19 -15
  22. data/support/3A79BD29.asc +49 -0
  23. data/support/5072E1F5.asc +5 -5
  24. data/support/C74CD1D8.asc +104 -0
  25. data/support/mysql_enc_to_ruby.rb +9 -3
  26. data/support/ruby_enc_to_mysql.rb +8 -5
  27. metadata +19 -62
  28. data/examples/eventmachine.rb +0 -21
  29. data/examples/threaded.rb +0 -18
  30. data/spec/configuration.yml.example +0 -11
  31. data/spec/em/em_spec.rb +0 -136
  32. data/spec/my.cnf.example +0 -9
  33. data/spec/mysql2/client_spec.rb +0 -1039
  34. data/spec/mysql2/error_spec.rb +0 -82
  35. data/spec/mysql2/result_spec.rb +0 -545
  36. data/spec/mysql2/statement_spec.rb +0 -776
  37. data/spec/rcov.opts +0 -3
  38. data/spec/spec_helper.rb +0 -108
  39. data/spec/ssl/ca-cert.pem +0 -17
  40. data/spec/ssl/ca-key.pem +0 -27
  41. data/spec/ssl/ca.cnf +0 -22
  42. data/spec/ssl/cert.cnf +0 -22
  43. data/spec/ssl/client-cert.pem +0 -17
  44. data/spec/ssl/client-key.pem +0 -27
  45. data/spec/ssl/client-req.pem +0 -15
  46. data/spec/ssl/gen_certs.sh +0 -48
  47. data/spec/ssl/pkcs8-client-key.pem +0 -28
  48. data/spec/ssl/pkcs8-server-key.pem +0 -28
  49. data/spec/ssl/server-cert.pem +0 -17
  50. data/spec/ssl/server-key.pem +0 -27
  51. data/spec/ssl/server-req.pem +0 -15
  52. data/spec/test_data +0 -1
data/ext/mysql2/result.c CHANGED
@@ -1,56 +1,43 @@
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
32
+ #endif
33
+
34
+ #ifndef NEW_TYPEDDATA_WRAPPER
35
+ #define TypedData_Get_Struct(obj, type, ignore, sval) Data_Get_Struct(obj, type, sval)
49
36
  #endif
50
37
 
51
38
  #define GET_RESULT(self) \
52
39
  mysql2_result_wrapper *wrapper; \
53
- Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
40
+ TypedData_Get_Struct(self, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
54
41
 
55
42
  typedef struct {
56
43
  int symbolizeKeys;
@@ -61,27 +48,28 @@ typedef struct {
61
48
  int streaming;
62
49
  ID db_timezone;
63
50
  ID app_timezone;
64
- VALUE block_given;
51
+ int block_given; /* boolean */
65
52
  } result_each_args;
66
53
 
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
54
  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;
55
+ static VALUE cMysql2Result, cDateTime, cDate;
56
+ static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
57
+ static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset,
58
+ intern_civil, intern_new_offset, intern_merge, intern_BigDecimal,
59
+ intern_query_options;
60
+ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
61
+ sym_application_timezone, sym_local, sym_utc, sym_cast_booleans,
62
+ sym_cache_rows, sym_cast, sym_stream, sym_name;
75
63
 
76
64
  /* Mark any VALUEs that are only referenced in C, so the GC won't get them. */
77
65
  static void rb_mysql_result_mark(void * wrapper) {
78
66
  mysql2_result_wrapper * w = wrapper;
79
67
  if (w) {
80
- rb_gc_mark(w->fields);
81
- rb_gc_mark(w->rows);
82
- rb_gc_mark(w->encoding);
83
- rb_gc_mark(w->client);
84
- rb_gc_mark(w->statement);
68
+ rb_gc_mark_movable(w->fields);
69
+ rb_gc_mark_movable(w->rows);
70
+ rb_gc_mark_movable(w->encoding);
71
+ rb_gc_mark_movable(w->client);
72
+ rb_gc_mark_movable(w->statement);
85
73
  }
86
74
  }
87
75
 
@@ -143,6 +131,48 @@ static void rb_mysql_result_free(void *ptr) {
143
131
  xfree(wrapper);
144
132
  }
145
133
 
134
+ static size_t rb_mysql_result_memsize(const void * wrapper) {
135
+ const mysql2_result_wrapper * w = wrapper;
136
+ size_t memsize = sizeof(*w);
137
+ if (w->stmt_wrapper) {
138
+ memsize += sizeof(*w->stmt_wrapper);
139
+ }
140
+ if (w->client_wrapper) {
141
+ memsize += sizeof(*w->client_wrapper);
142
+ }
143
+ return memsize;
144
+ }
145
+
146
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
147
+ static void rb_mysql_result_compact(void * wrapper) {
148
+ mysql2_result_wrapper * w = wrapper;
149
+ if (w) {
150
+ rb_mysql2_gc_location(w->fields);
151
+ rb_mysql2_gc_location(w->rows);
152
+ rb_mysql2_gc_location(w->encoding);
153
+ rb_mysql2_gc_location(w->client);
154
+ rb_mysql2_gc_location(w->statement);
155
+ }
156
+ }
157
+ #endif
158
+
159
+ static const rb_data_type_t rb_mysql_result_type = {
160
+ "rb_mysql_result",
161
+ {
162
+ rb_mysql_result_mark,
163
+ rb_mysql_result_free,
164
+ rb_mysql_result_memsize,
165
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
166
+ rb_mysql_result_compact,
167
+ #endif
168
+ },
169
+ 0,
170
+ 0,
171
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
172
+ RUBY_TYPED_FREE_IMMEDIATELY,
173
+ #endif
174
+ };
175
+
146
176
  static VALUE rb_mysql_result_free_(VALUE self) {
147
177
  GET_RESULT(self);
148
178
  rb_mysql_result_free_result(wrapper);
@@ -179,28 +209,25 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
179
209
  rb_field = rb_ary_entry(wrapper->fields, idx);
180
210
  if (rb_field == Qnil) {
181
211
  MYSQL_FIELD *field = NULL;
182
- #ifdef HAVE_RUBY_ENCODING_H
183
212
  rb_encoding *default_internal_enc = rb_default_internal_encoding();
184
213
  rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
185
- #endif
186
214
 
187
215
  field = mysql_fetch_field_direct(wrapper->result, idx);
188
216
  if (symbolize_keys) {
189
- #ifdef HAVE_RB_INTERN3
190
217
  rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
191
218
  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
219
  } 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) {
220
+ #ifdef HAVE_RB_ENC_INTERNED_STR
221
+ rb_field = rb_enc_interned_str(field->name, field->name_length, conn_enc);
222
+ if (default_internal_enc && default_internal_enc != conn_enc) {
223
+ rb_field = rb_str_to_interned_str(rb_str_export_to_enc(rb_field, default_internal_enc));
224
+ }
225
+ #else
226
+ rb_field = rb_enc_str_new(field->name, field->name_length, conn_enc);
227
+ if (default_internal_enc && default_internal_enc != conn_enc) {
202
228
  rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
203
229
  }
230
+ rb_obj_freeze(rb_field);
204
231
  #endif
205
232
  }
206
233
  rb_ary_store(wrapper->fields, idx, rb_field);
@@ -209,10 +236,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
209
236
  return rb_field;
210
237
  }
211
238
 
212
- #ifdef HAVE_RUBY_ENCODING_H
239
+ static VALUE rb_mysql_result_fetch_field_type(VALUE self, unsigned int idx) {
240
+ VALUE rb_field_type;
241
+ GET_RESULT(self);
242
+
243
+ if (wrapper->fieldTypes == Qnil) {
244
+ wrapper->numberOfFields = mysql_num_fields(wrapper->result);
245
+ wrapper->fieldTypes = rb_ary_new2(wrapper->numberOfFields);
246
+ }
247
+
248
+ rb_field_type = rb_ary_entry(wrapper->fieldTypes, idx);
249
+ if (rb_field_type == Qnil) {
250
+ MYSQL_FIELD *field = NULL;
251
+ rb_encoding *default_internal_enc = rb_default_internal_encoding();
252
+ rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
253
+ int precision;
254
+
255
+ field = mysql_fetch_field_direct(wrapper->result, idx);
256
+
257
+ switch(field->type) {
258
+ case MYSQL_TYPE_NULL: // NULL
259
+ rb_field_type = rb_str_new_cstr("null");
260
+ break;
261
+ case MYSQL_TYPE_TINY: // signed char
262
+ rb_field_type = rb_sprintf("tinyint(%ld)", field->length);
263
+ break;
264
+ case MYSQL_TYPE_SHORT: // short int
265
+ rb_field_type = rb_sprintf("smallint(%ld)", field->length);
266
+ break;
267
+ case MYSQL_TYPE_YEAR: // short int
268
+ rb_field_type = rb_sprintf("year(%ld)", field->length);
269
+ break;
270
+ case MYSQL_TYPE_INT24: // int
271
+ rb_field_type = rb_sprintf("mediumint(%ld)", field->length);
272
+ break;
273
+ case MYSQL_TYPE_LONG: // int
274
+ rb_field_type = rb_sprintf("int(%ld)", field->length);
275
+ break;
276
+ case MYSQL_TYPE_LONGLONG: // long long int
277
+ rb_field_type = rb_sprintf("bigint(%ld)", field->length);
278
+ break;
279
+ case MYSQL_TYPE_FLOAT: // float
280
+ rb_field_type = rb_sprintf("float(%ld,%d)", field->length, field->decimals);
281
+ break;
282
+ case MYSQL_TYPE_DOUBLE: // double
283
+ rb_field_type = rb_sprintf("double(%ld,%d)", field->length, field->decimals);
284
+ break;
285
+ case MYSQL_TYPE_TIME: // MYSQL_TIME
286
+ rb_field_type = rb_str_new_cstr("time");
287
+ break;
288
+ case MYSQL_TYPE_DATE: // MYSQL_TIME
289
+ case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
290
+ rb_field_type = rb_str_new_cstr("date");
291
+ break;
292
+ case MYSQL_TYPE_DATETIME: // MYSQL_TIME
293
+ rb_field_type = rb_str_new_cstr("datetime");
294
+ break;
295
+ case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
296
+ rb_field_type = rb_str_new_cstr("timestamp");
297
+ break;
298
+ case MYSQL_TYPE_DECIMAL: // char[]
299
+ case MYSQL_TYPE_NEWDECIMAL: // char[]
300
+ /*
301
+ Handle precision similar to this line from mysql's code:
302
+ https://github.com/mysql/mysql-server/blob/ea7d2e2d16ac03afdd9cb72a972a95981107bf51/sql/field.cc#L2246
303
+ */
304
+ precision = field->length - (field->decimals > 0 ? 2 : 1);
305
+ rb_field_type = rb_sprintf("decimal(%d,%d)", precision, field->decimals);
306
+ break;
307
+ case MYSQL_TYPE_STRING: // char[]
308
+ if (field->flags & ENUM_FLAG) {
309
+ rb_field_type = rb_str_new_cstr("enum");
310
+ } else if (field->flags & SET_FLAG) {
311
+ rb_field_type = rb_str_new_cstr("set");
312
+ } else {
313
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
314
+ rb_field_type = rb_sprintf("binary(%ld)", field->length);
315
+ } else {
316
+ rb_field_type = rb_sprintf("char(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
317
+ }
318
+ }
319
+ break;
320
+ case MYSQL_TYPE_VAR_STRING: // char[]
321
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
322
+ rb_field_type = rb_sprintf("varbinary(%ld)", field->length);
323
+ } else {
324
+ rb_field_type = rb_sprintf("varchar(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
325
+ }
326
+ break;
327
+ case MYSQL_TYPE_VARCHAR: // char[]
328
+ rb_field_type = rb_sprintf("varchar(%ld)", field->length / MYSQL2_MAX_BYTES_PER_CHAR);
329
+ break;
330
+ case MYSQL_TYPE_TINY_BLOB: // char[]
331
+ rb_field_type = rb_str_new_cstr("tinyblob");
332
+ break;
333
+ case MYSQL_TYPE_BLOB: // char[]
334
+ if (field->charsetnr == MYSQL2_BINARY_CHARSET) {
335
+ switch(field->length) {
336
+ case 255:
337
+ rb_field_type = rb_str_new_cstr("tinyblob");
338
+ break;
339
+ case 65535:
340
+ rb_field_type = rb_str_new_cstr("blob");
341
+ break;
342
+ case 16777215:
343
+ rb_field_type = rb_str_new_cstr("mediumblob");
344
+ break;
345
+ case 4294967295:
346
+ rb_field_type = rb_str_new_cstr("longblob");
347
+ default:
348
+ break;
349
+ }
350
+ } else {
351
+ if (field->length == (255 * MYSQL2_MAX_BYTES_PER_CHAR)) {
352
+ rb_field_type = rb_str_new_cstr("tinytext");
353
+ } else if (field->length == (65535 * MYSQL2_MAX_BYTES_PER_CHAR)) {
354
+ rb_field_type = rb_str_new_cstr("text");
355
+ } else if (field->length == (16777215 * MYSQL2_MAX_BYTES_PER_CHAR)) {
356
+ rb_field_type = rb_str_new_cstr("mediumtext");
357
+ } else if (field->length == 4294967295) {
358
+ rb_field_type = rb_str_new_cstr("longtext");
359
+ } else {
360
+ rb_field_type = rb_sprintf("text(%ld)", field->length);
361
+ }
362
+ }
363
+ break;
364
+ case MYSQL_TYPE_MEDIUM_BLOB: // char[]
365
+ rb_field_type = rb_str_new_cstr("mediumblob");
366
+ break;
367
+ case MYSQL_TYPE_LONG_BLOB: // char[]
368
+ rb_field_type = rb_str_new_cstr("longblob");
369
+ break;
370
+ case MYSQL_TYPE_BIT: // char[]
371
+ rb_field_type = rb_sprintf("bit(%ld)", field->length);
372
+ break;
373
+ case MYSQL_TYPE_SET: // char[]
374
+ rb_field_type = rb_str_new_cstr("set");
375
+ break;
376
+ case MYSQL_TYPE_ENUM: // char[]
377
+ rb_field_type = rb_str_new_cstr("enum");
378
+ break;
379
+ case MYSQL_TYPE_GEOMETRY: // char[]
380
+ rb_field_type = rb_str_new_cstr("geometry");
381
+ break;
382
+ case MYSQL_TYPE_JSON: // json
383
+ rb_field_type = rb_str_new_cstr("json");
384
+ break;
385
+ default:
386
+ rb_field_type = rb_str_new_cstr("unknown");
387
+ break;
388
+ }
389
+
390
+ rb_enc_associate(rb_field_type, conn_enc);
391
+ if (default_internal_enc) {
392
+ rb_field_type = rb_str_export_to_enc(rb_field_type, default_internal_enc);
393
+ }
394
+
395
+ rb_ary_store(wrapper->fieldTypes, idx, rb_field_type);
396
+ }
397
+
398
+ return rb_field_type;
399
+ }
400
+
213
401
  static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
214
402
  /* if binary flag is set, respect its wishes */
215
- if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
403
+ if (field.flags & BINARY_FLAG && field.charsetnr == MYSQL2_BINARY_CHARSET) {
216
404
  rb_enc_associate(val, binaryEncoding);
217
405
  } else if (!field.charsetnr) {
218
406
  /* MySQL 4.x may not provide an encoding, binary will get the bytes through */
@@ -222,7 +410,8 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
222
410
  const char *enc_name;
223
411
  int enc_index;
224
412
 
225
- enc_name = mysql2_mysql_enc_to_rb[field.charsetnr-1];
413
+ enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
414
+
226
415
  if (enc_name != NULL) {
227
416
  /* use the field encoding we were able to match */
228
417
  enc_index = rb_enc_find_index(enc_name);
@@ -238,7 +427,6 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
238
427
  }
239
428
  return val;
240
429
  }
241
- #endif
242
430
 
243
431
  /* Interpret microseconds digits left-aligned in fixed-width field.
244
432
  * e.g. 10.123 seconds means 10 seconds and 123000 microseconds,
@@ -262,8 +450,8 @@ static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields
262
450
  if (wrapper->result_buffers != NULL) return;
263
451
 
264
452
  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));
453
+ wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
454
+ wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
267
455
  wrapper->length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
268
456
 
269
457
  for (i = 0; i < wrapper->numberOfFields; i++) {
@@ -278,12 +466,12 @@ static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields
278
466
  wrapper->result_buffers[i].buffer_length = sizeof(signed char);
279
467
  break;
280
468
  case MYSQL_TYPE_SHORT: // short int
469
+ case MYSQL_TYPE_YEAR: // short int
281
470
  wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(short int));
282
471
  wrapper->result_buffers[i].buffer_length = sizeof(short int);
283
472
  break;
284
473
  case MYSQL_TYPE_INT24: // int
285
474
  case MYSQL_TYPE_LONG: // int
286
- case MYSQL_TYPE_YEAR: // int
287
475
  wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(int));
288
476
  wrapper->result_buffers[i].buffer_length = sizeof(int);
289
477
  break;
@@ -335,16 +523,12 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
335
523
  VALUE rowVal;
336
524
  unsigned int i = 0;
337
525
 
338
- #ifdef HAVE_RUBY_ENCODING_H
339
526
  rb_encoding *default_internal_enc;
340
527
  rb_encoding *conn_enc;
341
- #endif
342
528
  GET_RESULT(self);
343
529
 
344
- #ifdef HAVE_RUBY_ENCODING_H
345
530
  default_internal_enc = rb_default_internal_encoding();
346
531
  conn_enc = rb_to_encoding(wrapper->encoding);
347
- #endif
348
532
 
349
533
  if (wrapper->fields == Qnil) {
350
534
  wrapper->numberOfFields = mysql_num_fields(wrapper->result);
@@ -413,6 +597,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
413
597
  }
414
598
  break;
415
599
  case MYSQL_TYPE_SHORT: // short int
600
+ case MYSQL_TYPE_YEAR: // short int
416
601
  if (result_buffer->is_unsigned) {
417
602
  val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
418
603
  } else {
@@ -421,7 +606,6 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
421
606
  break;
422
607
  case MYSQL_TYPE_INT24: // int
423
608
  case MYSQL_TYPE_LONG: // int
424
- case MYSQL_TYPE_YEAR: // int
425
609
  if (result_buffer->is_unsigned) {
426
610
  val = UINT2NUM(*((unsigned int*)result_buffer->buffer));
427
611
  } else {
@@ -492,7 +676,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
492
676
  }
493
677
  case MYSQL_TYPE_DECIMAL: // char[]
494
678
  case MYSQL_TYPE_NEWDECIMAL: // char[]
495
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
679
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
496
680
  break;
497
681
  case MYSQL_TYPE_STRING: // char[]
498
682
  case MYSQL_TYPE_VAR_STRING: // char[]
@@ -506,9 +690,7 @@ static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, co
506
690
  case MYSQL_TYPE_GEOMETRY: // char[]
507
691
  default:
508
692
  val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
509
- #ifdef HAVE_RUBY_ENCODING_H
510
693
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
511
- #endif
512
694
  break;
513
695
  }
514
696
  }
@@ -530,16 +712,12 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
530
712
  unsigned int i = 0;
531
713
  unsigned long * fieldLengths;
532
714
  void * ptr;
533
- #ifdef HAVE_RUBY_ENCODING_H
534
715
  rb_encoding *default_internal_enc;
535
716
  rb_encoding *conn_enc;
536
- #endif
537
717
  GET_RESULT(self);
538
718
 
539
- #ifdef HAVE_RUBY_ENCODING_H
540
719
  default_internal_enc = rb_default_internal_encoding();
541
720
  conn_enc = rb_to_encoding(wrapper->encoding);
542
- #endif
543
721
 
544
722
  ptr = wrapper->result;
545
723
  row = (MYSQL_ROW)rb_thread_call_without_gvl(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
@@ -569,9 +747,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
569
747
  val = Qnil;
570
748
  } else {
571
749
  val = rb_str_new(row[i], fieldLengths[i]);
572
- #ifdef HAVE_RUBY_ENCODING_H
573
750
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
574
- #endif
575
751
  }
576
752
  } else {
577
753
  switch(type) {
@@ -602,9 +778,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
602
778
  if (fields[i].decimals == 0) {
603
779
  val = rb_cstr2inum(row[i], 10);
604
780
  } else if (strtod(row[i], NULL) == 0.000000){
605
- val = rb_funcall(cBigDecimal, intern_new, 1, opt_decimal_zero);
781
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, opt_decimal_zero);
606
782
  }else{
607
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(row[i], fieldLengths[i]));
783
+ val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(row[i], fieldLengths[i]));
608
784
  }
609
785
  break;
610
786
  case MYSQL_TYPE_FLOAT: /* FLOAT field */
@@ -722,9 +898,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const r
722
898
  case MYSQL_TYPE_GEOMETRY: /* Spatial fielda */
723
899
  default:
724
900
  val = rb_str_new(row[i], fieldLengths[i]);
725
- #ifdef HAVE_RUBY_ENCODING_H
726
901
  val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
727
- #endif
728
902
  break;
729
903
  }
730
904
  }
@@ -751,7 +925,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
751
925
 
752
926
  GET_RESULT(self);
753
927
 
754
- defaults = rb_iv_get(self, "@query_options");
928
+ defaults = rb_ivar_get(self, intern_query_options);
755
929
  Check_Type(defaults, T_HASH);
756
930
  if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
757
931
  symbolizeKeys = 1;
@@ -771,6 +945,25 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
771
945
  return wrapper->fields;
772
946
  }
773
947
 
948
+ static VALUE rb_mysql_result_fetch_field_types(VALUE self) {
949
+ unsigned int i = 0;
950
+
951
+ GET_RESULT(self);
952
+
953
+ if (wrapper->fieldTypes == Qnil) {
954
+ wrapper->numberOfFields = mysql_num_fields(wrapper->result);
955
+ wrapper->fieldTypes = rb_ary_new2(wrapper->numberOfFields);
956
+ }
957
+
958
+ if ((my_ulonglong)RARRAY_LEN(wrapper->fieldTypes) != wrapper->numberOfFields) {
959
+ for (i=0; i<wrapper->numberOfFields; i++) {
960
+ rb_mysql_result_fetch_field_type(self, i);
961
+ }
962
+ }
963
+
964
+ return wrapper->fieldTypes;
965
+ }
966
+
774
967
  static VALUE rb_mysql_result_each_(VALUE self,
775
968
  VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
776
969
  const result_each_args *args)
@@ -796,7 +989,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
796
989
  row = fetch_row_func(self, fields, args);
797
990
  if (row != Qnil) {
798
991
  wrapper->numberOfRows++;
799
- if (args->block_given != Qnil) {
992
+ if (args->block_given) {
800
993
  rb_yield(row);
801
994
  }
802
995
  }
@@ -846,7 +1039,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
846
1039
  return Qnil;
847
1040
  }
848
1041
 
849
- if (args->block_given != Qnil) {
1042
+ if (args->block_given) {
850
1043
  rb_yield(row);
851
1044
  }
852
1045
  }
@@ -864,7 +1057,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
864
1057
 
865
1058
  static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
866
1059
  result_each_args args;
867
- VALUE defaults, opts, block, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
1060
+ VALUE defaults, opts, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
868
1061
  ID db_timezone, app_timezone, dbTz, appTz;
869
1062
  int symbolizeKeys, asArray, castBool, cacheRows, cast;
870
1063
 
@@ -874,9 +1067,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
874
1067
  rb_raise(cMysql2Error, "Statement handle already closed");
875
1068
  }
876
1069
 
877
- defaults = rb_iv_get(self, "@query_options");
1070
+ defaults = rb_ivar_get(self, intern_query_options);
878
1071
  Check_Type(defaults, T_HASH);
879
- if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
1072
+
1073
+ // A block can be passed to this method, but since we don't call the block directly from C,
1074
+ // we don't need to capture it into a variable here with the "&" scan arg.
1075
+ if (rb_scan_args(argc, argv, "01", &opts) == 1) {
880
1076
  opts = rb_funcall(defaults, intern_merge, 1, opts);
881
1077
  } else {
882
1078
  opts = defaults;
@@ -942,7 +1138,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
942
1138
  args.cast = cast;
943
1139
  args.db_timezone = db_timezone;
944
1140
  args.app_timezone = app_timezone;
945
- args.block_given = block;
1141
+ args.block_given = rb_block_given_p();
946
1142
 
947
1143
  if (wrapper->stmt_wrapper) {
948
1144
  fetch_row_func = rb_mysql_result_fetch_row_stmt;
@@ -979,13 +1175,18 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
979
1175
  VALUE obj;
980
1176
  mysql2_result_wrapper * wrapper;
981
1177
 
1178
+ #ifdef NEW_TYPEDDATA_WRAPPER
1179
+ obj = TypedData_Make_Struct(cMysql2Result, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
1180
+ #else
982
1181
  obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
1182
+ #endif
983
1183
  wrapper->numberOfFields = 0;
984
1184
  wrapper->numberOfRows = 0;
985
1185
  wrapper->lastRowProcessed = 0;
986
1186
  wrapper->resultFreed = 0;
987
1187
  wrapper->result = r;
988
1188
  wrapper->fields = Qnil;
1189
+ wrapper->fieldTypes = Qnil;
989
1190
  wrapper->rows = Qnil;
990
1191
  wrapper->encoding = encoding;
991
1192
  wrapper->streamingComplete = 0;
@@ -1007,7 +1208,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
1007
1208
  }
1008
1209
 
1009
1210
  rb_obj_call_init(obj, 0, NULL);
1010
- rb_iv_set(obj, "@query_options", options);
1211
+ rb_ivar_set(obj, intern_query_options, options);
1011
1212
 
1012
1213
  /* Options that cannot be changed in results.each(...) { |row| }
1013
1214
  * should be processed here. */
@@ -1017,13 +1218,18 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
1017
1218
  }
1018
1219
 
1019
1220
  void init_mysql2_result() {
1020
- cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
1021
1221
  cDate = rb_const_get(rb_cObject, rb_intern("Date"));
1222
+ rb_global_variable(&cDate);
1022
1223
  cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
1224
+ rb_global_variable(&cDateTime);
1023
1225
 
1024
1226
  cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
1227
+ rb_undef_alloc_func(cMysql2Result);
1228
+ rb_global_variable(&cMysql2Result);
1229
+
1025
1230
  rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
1026
1231
  rb_define_method(cMysql2Result, "fields", rb_mysql_result_fetch_fields, 0);
1232
+ rb_define_method(cMysql2Result, "field_types", rb_mysql_result_fetch_field_types, 0);
1027
1233
  rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0);
1028
1234
  rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
1029
1235
  rb_define_alias(cMysql2Result, "size", "count");
@@ -1036,6 +1242,8 @@ void init_mysql2_result() {
1036
1242
  intern_local_offset = rb_intern("local_offset");
1037
1243
  intern_civil = rb_intern("civil");
1038
1244
  intern_new_offset = rb_intern("new_offset");
1245
+ intern_BigDecimal = rb_intern("BigDecimal");
1246
+ intern_query_options = rb_intern("@query_options");
1039
1247
 
1040
1248
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
1041
1249
  sym_as = ID2SYM(rb_intern("as"));
@@ -1058,7 +1266,5 @@ void init_mysql2_result() {
1058
1266
  opt_time_month = INT2NUM(1);
1059
1267
  opt_utc_offset = INT2NUM(0);
1060
1268
 
1061
- #ifdef HAVE_RUBY_ENCODING_H
1062
1269
  binaryEncoding = rb_enc_find("binary");
1063
- #endif
1064
1270
  }
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