mysql2 0.3.21-x86-mingw32 → 0.4.0-x86-mingw32
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +28 -6
- data/examples/threaded.rb +4 -6
- data/ext/mysql2/client.c +54 -46
- data/ext/mysql2/client.h +21 -0
- data/ext/mysql2/extconf.rb +20 -23
- data/ext/mysql2/mysql2_ext.c +1 -0
- data/ext/mysql2/mysql2_ext.h +1 -0
- data/ext/mysql2/mysql_enc_name_to_ruby.h +6 -6
- data/ext/mysql2/result.c +473 -94
- data/ext/mysql2/result.h +8 -1
- data/ext/mysql2/statement.c +454 -0
- data/ext/mysql2/statement.h +22 -0
- data/lib/mysql2.rb +2 -18
- data/lib/mysql2/1.8/mysql2.so +0 -0
- data/lib/mysql2/1.9/mysql2.so +0 -0
- data/lib/mysql2/2.0/mysql2.so +0 -0
- data/lib/mysql2/2.1/mysql2.so +0 -0
- data/lib/mysql2/2.2/mysql2.so +0 -0
- data/lib/mysql2/client.rb +9 -2
- data/lib/mysql2/error.rb +8 -20
- data/lib/mysql2/field.rb +4 -0
- data/lib/mysql2/statement.rb +5 -0
- data/lib/mysql2/version.rb +1 -1
- data/spec/em/em_spec.rb +13 -13
- data/spec/mysql2/client_spec.rb +284 -277
- data/spec/mysql2/error_spec.rb +37 -36
- data/spec/mysql2/result_spec.rb +184 -193
- data/spec/mysql2/statement_spec.rb +598 -0
- data/spec/spec_helper.rb +7 -0
- metadata +15 -48
- data/lib/mysql2/2.3/mysql2.so +0 -0
data/ext/mysql2/mysql2_ext.c
CHANGED
data/ext/mysql2/mysql2_ext.h
CHANGED
@@ -40,9 +40,9 @@ inline
|
|
40
40
|
#endif
|
41
41
|
#endif
|
42
42
|
static unsigned int
|
43
|
-
mysql2_mysql_enc_name_to_rb_hash
|
43
|
+
mysql2_mysql_enc_name_to_rb_hash(str, len)
|
44
44
|
register const char *str;
|
45
|
-
register unsigned int len;
|
45
|
+
register const unsigned int len;
|
46
46
|
{
|
47
47
|
static const unsigned char asso_values[] =
|
48
48
|
{
|
@@ -83,9 +83,9 @@ __attribute__ ((__gnu_inline__))
|
|
83
83
|
#endif
|
84
84
|
#endif
|
85
85
|
const struct mysql2_mysql_enc_name_to_rb_map *
|
86
|
-
mysql2_mysql_enc_name_to_rb
|
86
|
+
mysql2_mysql_enc_name_to_rb(str, len)
|
87
87
|
register const char *str;
|
88
|
-
register unsigned int len;
|
88
|
+
register const unsigned int len;
|
89
89
|
{
|
90
90
|
enum
|
91
91
|
{
|
@@ -154,9 +154,9 @@ mysql2_mysql_enc_name_to_rb (str, len)
|
|
154
154
|
|
155
155
|
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
156
156
|
{
|
157
|
-
register int key = mysql2_mysql_enc_name_to_rb_hash
|
157
|
+
register const unsigned int key = mysql2_mysql_enc_name_to_rb_hash(str, len);
|
158
158
|
|
159
|
-
if (key <= MAX_HASH_VALUE
|
159
|
+
if (key <= MAX_HASH_VALUE)
|
160
160
|
{
|
161
161
|
register const char *s = wordlist[key].name;
|
162
162
|
|
data/ext/mysql2/result.c
CHANGED
@@ -54,8 +54,20 @@ static rb_encoding *binaryEncoding;
|
|
54
54
|
mysql2_result_wrapper *wrapper; \
|
55
55
|
Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
|
56
56
|
|
57
|
+
typedef struct {
|
58
|
+
int symbolizeKeys;
|
59
|
+
int asArray;
|
60
|
+
int castBool;
|
61
|
+
int cacheRows;
|
62
|
+
int cast;
|
63
|
+
int streaming;
|
64
|
+
ID db_timezone;
|
65
|
+
ID app_timezone;
|
66
|
+
VALUE block_given;
|
67
|
+
} result_each_args;
|
68
|
+
|
69
|
+
VALUE cBigDecimal, cDateTime, cDate;
|
57
70
|
static VALUE cMysql2Result;
|
58
|
-
static VALUE cBigDecimal, cDate, cDateTime;
|
59
71
|
static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
|
60
72
|
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
61
73
|
static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset, intern_civil, intern_new_offset;
|
@@ -63,6 +75,7 @@ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone, sym_a
|
|
63
75
|
sym_local, sym_utc, sym_cast_booleans, sym_cache_rows, sym_cast, sym_stream, sym_name;
|
64
76
|
static ID intern_merge;
|
65
77
|
|
78
|
+
/* Mark any VALUEs that are only referenced in C, so the GC won't get them. */
|
66
79
|
static void rb_mysql_result_mark(void * wrapper) {
|
67
80
|
mysql2_result_wrapper * w = wrapper;
|
68
81
|
if (w) {
|
@@ -70,13 +83,44 @@ static void rb_mysql_result_mark(void * wrapper) {
|
|
70
83
|
rb_gc_mark(w->rows);
|
71
84
|
rb_gc_mark(w->encoding);
|
72
85
|
rb_gc_mark(w->client);
|
86
|
+
rb_gc_mark(w->statement);
|
73
87
|
}
|
74
88
|
}
|
75
89
|
|
76
90
|
/* this may be called manually or during GC */
|
77
91
|
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
|
78
|
-
if (wrapper
|
92
|
+
if (!wrapper) return;
|
93
|
+
|
94
|
+
if (wrapper->resultFreed != 1) {
|
95
|
+
if (wrapper->stmt_wrapper) {
|
96
|
+
mysql_stmt_free_result(wrapper->stmt_wrapper->stmt);
|
97
|
+
|
98
|
+
/* MySQL BUG? If the statement handle was previously used, and so
|
99
|
+
* mysql_stmt_bind_result was called, and if that result set and bind buffers were freed,
|
100
|
+
* MySQL still thinks the result set buffer is available and will prefetch the
|
101
|
+
* first result in mysql_stmt_execute. This will corrupt or crash the program.
|
102
|
+
* By setting bind_result_done back to 0, we make MySQL think that a result set
|
103
|
+
* has never been bound to this statement handle before to prevent the prefetch.
|
104
|
+
*/
|
105
|
+
wrapper->stmt_wrapper->stmt->bind_result_done = 0;
|
106
|
+
|
107
|
+
if (wrapper->result_buffers) {
|
108
|
+
unsigned int i;
|
109
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
110
|
+
if (wrapper->result_buffers[i].buffer) {
|
111
|
+
xfree(wrapper->result_buffers[i].buffer);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
xfree(wrapper->result_buffers);
|
115
|
+
xfree(wrapper->is_null);
|
116
|
+
xfree(wrapper->error);
|
117
|
+
xfree(wrapper->length);
|
118
|
+
}
|
119
|
+
/* Clue that the next statement execute will need to allocate a new result buffer. */
|
120
|
+
wrapper->result_buffers = NULL;
|
121
|
+
}
|
79
122
|
/* FIXME: this may call flush_use_result, which can hit the socket */
|
123
|
+
/* For prepared statements, wrapper->result is the result metadata */
|
80
124
|
mysql_free_result(wrapper->result);
|
81
125
|
wrapper->resultFreed = 1;
|
82
126
|
}
|
@@ -84,7 +128,7 @@ static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
|
|
84
128
|
|
85
129
|
/* this is called during GC */
|
86
130
|
static void rb_mysql_result_free(void *ptr) {
|
87
|
-
mysql2_result_wrapper *
|
131
|
+
mysql2_result_wrapper *wrapper = ptr;
|
88
132
|
rb_mysql_result_free_result(wrapper);
|
89
133
|
|
90
134
|
// If the GC gets to client first it will be nil
|
@@ -92,6 +136,10 @@ static void rb_mysql_result_free(void *ptr) {
|
|
92
136
|
decr_mysql2_client(wrapper->client_wrapper);
|
93
137
|
}
|
94
138
|
|
139
|
+
if (wrapper->statement != Qnil) {
|
140
|
+
decr_mysql2_stmt(wrapper->stmt_wrapper);
|
141
|
+
}
|
142
|
+
|
95
143
|
xfree(wrapper);
|
96
144
|
}
|
97
145
|
|
@@ -106,6 +154,14 @@ static void *nogvl_fetch_row(void *ptr) {
|
|
106
154
|
return mysql_fetch_row(result);
|
107
155
|
}
|
108
156
|
|
157
|
+
static void *nogvl_stmt_fetch(void *ptr) {
|
158
|
+
MYSQL_STMT *stmt = ptr;
|
159
|
+
uintptr_t r = mysql_stmt_fetch(stmt);
|
160
|
+
|
161
|
+
return (void *)r;
|
162
|
+
}
|
163
|
+
|
164
|
+
|
109
165
|
static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int symbolize_keys) {
|
110
166
|
VALUE rb_field;
|
111
167
|
GET_RESULT(self);
|
@@ -185,7 +241,7 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
185
241
|
*/
|
186
242
|
static unsigned int msec_char_to_uint(char *msec_char, size_t len)
|
187
243
|
{
|
188
|
-
|
244
|
+
size_t i;
|
189
245
|
for (i = 0; i < (len - 1); i++) {
|
190
246
|
if (msec_char[i] == '\0') {
|
191
247
|
msec_char[i] = '0';
|
@@ -194,7 +250,283 @@ static unsigned int msec_char_to_uint(char *msec_char, size_t len)
|
|
194
250
|
return (unsigned int)strtoul(msec_char, NULL, 10);
|
195
251
|
}
|
196
252
|
|
197
|
-
static
|
253
|
+
static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields) {
|
254
|
+
unsigned int i;
|
255
|
+
GET_RESULT(self);
|
256
|
+
|
257
|
+
if (wrapper->result_buffers != NULL) return;
|
258
|
+
|
259
|
+
wrapper->result_buffers = xcalloc(wrapper->numberOfFields, sizeof(MYSQL_BIND));
|
260
|
+
wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
|
261
|
+
wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
|
262
|
+
wrapper->length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
|
263
|
+
|
264
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
265
|
+
wrapper->result_buffers[i].buffer_type = fields[i].type;
|
266
|
+
|
267
|
+
// mysql type | C type
|
268
|
+
switch(fields[i].type) {
|
269
|
+
case MYSQL_TYPE_NULL: // NULL
|
270
|
+
break;
|
271
|
+
case MYSQL_TYPE_TINY: // signed char
|
272
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(signed char));
|
273
|
+
wrapper->result_buffers[i].buffer_length = sizeof(signed char);
|
274
|
+
break;
|
275
|
+
case MYSQL_TYPE_SHORT: // short int
|
276
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(short int));
|
277
|
+
wrapper->result_buffers[i].buffer_length = sizeof(short int);
|
278
|
+
break;
|
279
|
+
case MYSQL_TYPE_INT24: // int
|
280
|
+
case MYSQL_TYPE_LONG: // int
|
281
|
+
case MYSQL_TYPE_YEAR: // int
|
282
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(int));
|
283
|
+
wrapper->result_buffers[i].buffer_length = sizeof(int);
|
284
|
+
break;
|
285
|
+
case MYSQL_TYPE_LONGLONG: // long long int
|
286
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(long long int));
|
287
|
+
wrapper->result_buffers[i].buffer_length = sizeof(long long int);
|
288
|
+
break;
|
289
|
+
case MYSQL_TYPE_FLOAT: // float
|
290
|
+
case MYSQL_TYPE_DOUBLE: // double
|
291
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(double));
|
292
|
+
wrapper->result_buffers[i].buffer_length = sizeof(double);
|
293
|
+
break;
|
294
|
+
case MYSQL_TYPE_TIME: // MYSQL_TIME
|
295
|
+
case MYSQL_TYPE_DATE: // MYSQL_TIME
|
296
|
+
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
|
297
|
+
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
|
298
|
+
case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
|
299
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(MYSQL_TIME));
|
300
|
+
wrapper->result_buffers[i].buffer_length = sizeof(MYSQL_TIME);
|
301
|
+
break;
|
302
|
+
case MYSQL_TYPE_DECIMAL: // char[]
|
303
|
+
case MYSQL_TYPE_NEWDECIMAL: // char[]
|
304
|
+
case MYSQL_TYPE_STRING: // char[]
|
305
|
+
case MYSQL_TYPE_VAR_STRING: // char[]
|
306
|
+
case MYSQL_TYPE_VARCHAR: // char[]
|
307
|
+
case MYSQL_TYPE_TINY_BLOB: // char[]
|
308
|
+
case MYSQL_TYPE_BLOB: // char[]
|
309
|
+
case MYSQL_TYPE_MEDIUM_BLOB: // char[]
|
310
|
+
case MYSQL_TYPE_LONG_BLOB: // char[]
|
311
|
+
case MYSQL_TYPE_BIT: // char[]
|
312
|
+
case MYSQL_TYPE_SET: // char[]
|
313
|
+
case MYSQL_TYPE_ENUM: // char[]
|
314
|
+
case MYSQL_TYPE_GEOMETRY: // char[]
|
315
|
+
wrapper->result_buffers[i].buffer = xmalloc(fields[i].max_length);
|
316
|
+
wrapper->result_buffers[i].buffer_length = fields[i].max_length;
|
317
|
+
break;
|
318
|
+
default:
|
319
|
+
rb_raise(cMysql2Error, "unhandled mysql type: %d", fields[i].type);
|
320
|
+
}
|
321
|
+
|
322
|
+
wrapper->result_buffers[i].is_null = &wrapper->is_null[i];
|
323
|
+
wrapper->result_buffers[i].length = &wrapper->length[i];
|
324
|
+
wrapper->result_buffers[i].error = &wrapper->error[i];
|
325
|
+
wrapper->result_buffers[i].is_unsigned = ((fields[i].flags & UNSIGNED_FLAG) != 0);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, const result_each_args *args)
|
330
|
+
{
|
331
|
+
VALUE rowVal;
|
332
|
+
unsigned int i = 0;
|
333
|
+
|
334
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
335
|
+
rb_encoding *default_internal_enc;
|
336
|
+
rb_encoding *conn_enc;
|
337
|
+
#endif
|
338
|
+
GET_RESULT(self);
|
339
|
+
|
340
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
341
|
+
default_internal_enc = rb_default_internal_encoding();
|
342
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
343
|
+
#endif
|
344
|
+
|
345
|
+
if (args->asArray) {
|
346
|
+
rowVal = rb_ary_new2(wrapper->numberOfFields);
|
347
|
+
} else {
|
348
|
+
rowVal = rb_hash_new();
|
349
|
+
}
|
350
|
+
if (wrapper->fields == Qnil) {
|
351
|
+
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
352
|
+
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
353
|
+
}
|
354
|
+
|
355
|
+
if (wrapper->result_buffers == NULL) {
|
356
|
+
rb_mysql_result_alloc_result_buffers(self, fields);
|
357
|
+
}
|
358
|
+
|
359
|
+
if (mysql_stmt_bind_result(wrapper->stmt_wrapper->stmt, wrapper->result_buffers)) {
|
360
|
+
rb_raise_mysql2_stmt_error2(wrapper->stmt_wrapper->stmt
|
361
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
362
|
+
, conn_enc
|
363
|
+
#endif
|
364
|
+
);
|
365
|
+
}
|
366
|
+
|
367
|
+
{
|
368
|
+
switch((uintptr_t)rb_thread_call_without_gvl(nogvl_stmt_fetch, wrapper->stmt_wrapper->stmt, RUBY_UBF_IO, 0)) {
|
369
|
+
case 0:
|
370
|
+
/* success */
|
371
|
+
break;
|
372
|
+
|
373
|
+
case 1:
|
374
|
+
/* error */
|
375
|
+
rb_raise_mysql2_stmt_error2(wrapper->stmt_wrapper->stmt
|
376
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
377
|
+
, conn_enc
|
378
|
+
#endif
|
379
|
+
);
|
380
|
+
|
381
|
+
case MYSQL_NO_DATA:
|
382
|
+
/* no more row */
|
383
|
+
return Qnil;
|
384
|
+
|
385
|
+
case MYSQL_DATA_TRUNCATED:
|
386
|
+
rb_raise(cMysql2Error, "IMPLBUG: caught MYSQL_DATA_TRUNCATED. should not come here as buffer_length is set to fields[i].max_length.");
|
387
|
+
}
|
388
|
+
}
|
389
|
+
|
390
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
391
|
+
VALUE field = rb_mysql_result_fetch_field(self, i, args->symbolizeKeys);
|
392
|
+
VALUE val = Qnil;
|
393
|
+
MYSQL_TIME *ts;
|
394
|
+
|
395
|
+
if (wrapper->is_null[i]) {
|
396
|
+
val = Qnil;
|
397
|
+
} else {
|
398
|
+
const MYSQL_BIND* const result_buffer = &wrapper->result_buffers[i];
|
399
|
+
|
400
|
+
switch(result_buffer->buffer_type) {
|
401
|
+
case MYSQL_TYPE_TINY: // signed char
|
402
|
+
if (args->castBool && fields[i].length == 1) {
|
403
|
+
val = (*((unsigned char*)result_buffer->buffer) != 0) ? Qtrue : Qfalse;
|
404
|
+
break;
|
405
|
+
}
|
406
|
+
if (result_buffer->is_unsigned) {
|
407
|
+
val = UINT2NUM(*((unsigned char*)result_buffer->buffer));
|
408
|
+
} else {
|
409
|
+
val = INT2NUM(*((signed char*)result_buffer->buffer));
|
410
|
+
}
|
411
|
+
break;
|
412
|
+
case MYSQL_TYPE_SHORT: // short int
|
413
|
+
if (result_buffer->is_unsigned) {
|
414
|
+
val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
|
415
|
+
} else {
|
416
|
+
val = INT2NUM(*((short int*)result_buffer->buffer));
|
417
|
+
}
|
418
|
+
break;
|
419
|
+
case MYSQL_TYPE_INT24: // int
|
420
|
+
case MYSQL_TYPE_LONG: // int
|
421
|
+
case MYSQL_TYPE_YEAR: // int
|
422
|
+
if (result_buffer->is_unsigned) {
|
423
|
+
val = UINT2NUM(*((unsigned int*)result_buffer->buffer));
|
424
|
+
} else {
|
425
|
+
val = INT2NUM(*((int*)result_buffer->buffer));
|
426
|
+
}
|
427
|
+
break;
|
428
|
+
case MYSQL_TYPE_LONGLONG: // long long int
|
429
|
+
if (result_buffer->is_unsigned) {
|
430
|
+
val = ULL2NUM(*((unsigned long long int*)result_buffer->buffer));
|
431
|
+
} else {
|
432
|
+
val = LL2NUM(*((long long int*)result_buffer->buffer));
|
433
|
+
}
|
434
|
+
break;
|
435
|
+
case MYSQL_TYPE_FLOAT: // float
|
436
|
+
val = rb_float_new((double)(*((float*)result_buffer->buffer)));
|
437
|
+
break;
|
438
|
+
case MYSQL_TYPE_DOUBLE: // double
|
439
|
+
val = rb_float_new((double)(*((double*)result_buffer->buffer)));
|
440
|
+
break;
|
441
|
+
case MYSQL_TYPE_DATE: // MYSQL_TIME
|
442
|
+
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
|
443
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
444
|
+
val = rb_funcall(cDate, intern_new, 3, INT2NUM(ts->year), INT2NUM(ts->month), INT2NUM(ts->day));
|
445
|
+
break;
|
446
|
+
case MYSQL_TYPE_TIME: // MYSQL_TIME
|
447
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
448
|
+
val = rb_funcall(rb_cTime, args->db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), ULONG2NUM(ts->second_part));
|
449
|
+
if (!NIL_P(args->app_timezone)) {
|
450
|
+
if (args->app_timezone == intern_local) {
|
451
|
+
val = rb_funcall(val, intern_localtime, 0);
|
452
|
+
} else { // utc
|
453
|
+
val = rb_funcall(val, intern_utc, 0);
|
454
|
+
}
|
455
|
+
}
|
456
|
+
break;
|
457
|
+
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
|
458
|
+
case MYSQL_TYPE_TIMESTAMP: { // MYSQL_TIME
|
459
|
+
uint64_t seconds;
|
460
|
+
|
461
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
462
|
+
seconds = (ts->year*31557600ULL) + (ts->month*2592000ULL) + (ts->day*86400ULL) + (ts->hour*3600ULL) + (ts->minute*60ULL) + ts->second;
|
463
|
+
|
464
|
+
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
|
465
|
+
VALUE offset = INT2NUM(0);
|
466
|
+
if (args->db_timezone == intern_local) {
|
467
|
+
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
468
|
+
}
|
469
|
+
val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), offset);
|
470
|
+
if (!NIL_P(args->app_timezone)) {
|
471
|
+
if (args->app_timezone == intern_local) {
|
472
|
+
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
473
|
+
val = rb_funcall(val, intern_new_offset, 1, offset);
|
474
|
+
} else { // utc
|
475
|
+
val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
|
476
|
+
}
|
477
|
+
}
|
478
|
+
} else {
|
479
|
+
val = rb_funcall(rb_cTime, args->db_timezone, 7, UINT2NUM(ts->year), UINT2NUM(ts->month), UINT2NUM(ts->day), UINT2NUM(ts->hour), UINT2NUM(ts->minute), UINT2NUM(ts->second), ULONG2NUM(ts->second_part));
|
480
|
+
if (!NIL_P(args->app_timezone)) {
|
481
|
+
if (args->app_timezone == intern_local) {
|
482
|
+
val = rb_funcall(val, intern_localtime, 0);
|
483
|
+
} else { // utc
|
484
|
+
val = rb_funcall(val, intern_utc, 0);
|
485
|
+
}
|
486
|
+
}
|
487
|
+
}
|
488
|
+
break;
|
489
|
+
}
|
490
|
+
case MYSQL_TYPE_DECIMAL: // char[]
|
491
|
+
case MYSQL_TYPE_NEWDECIMAL: // char[]
|
492
|
+
val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
|
493
|
+
break;
|
494
|
+
case MYSQL_TYPE_STRING: // char[]
|
495
|
+
case MYSQL_TYPE_VAR_STRING: // char[]
|
496
|
+
case MYSQL_TYPE_VARCHAR: // char[]
|
497
|
+
case MYSQL_TYPE_TINY_BLOB: // char[]
|
498
|
+
case MYSQL_TYPE_BLOB: // char[]
|
499
|
+
case MYSQL_TYPE_MEDIUM_BLOB: // char[]
|
500
|
+
case MYSQL_TYPE_LONG_BLOB: // char[]
|
501
|
+
case MYSQL_TYPE_BIT: // char[]
|
502
|
+
case MYSQL_TYPE_SET: // char[]
|
503
|
+
case MYSQL_TYPE_ENUM: // char[]
|
504
|
+
case MYSQL_TYPE_GEOMETRY: // char[]
|
505
|
+
val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
|
506
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
507
|
+
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
508
|
+
#endif
|
509
|
+
break;
|
510
|
+
default:
|
511
|
+
rb_raise(cMysql2Error, "unhandled buffer type: %d",
|
512
|
+
result_buffer->buffer_type);
|
513
|
+
break;
|
514
|
+
}
|
515
|
+
}
|
516
|
+
|
517
|
+
if (args->asArray) {
|
518
|
+
rb_ary_push(rowVal, val);
|
519
|
+
} else {
|
520
|
+
rb_hash_aset(rowVal, field, val);
|
521
|
+
}
|
522
|
+
}
|
523
|
+
|
524
|
+
return rowVal;
|
525
|
+
}
|
526
|
+
|
527
|
+
|
528
|
+
static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const result_each_args *args)
|
529
|
+
{
|
198
530
|
VALUE rowVal;
|
199
531
|
MYSQL_ROW row;
|
200
532
|
unsigned int i = 0;
|
@@ -217,7 +549,7 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
217
549
|
return Qnil;
|
218
550
|
}
|
219
551
|
|
220
|
-
if (asArray) {
|
552
|
+
if (args->asArray) {
|
221
553
|
rowVal = rb_ary_new2(wrapper->numberOfFields);
|
222
554
|
} else {
|
223
555
|
rowVal = rb_hash_new();
|
@@ -229,12 +561,12 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
229
561
|
}
|
230
562
|
|
231
563
|
for (i = 0; i < wrapper->numberOfFields; i++) {
|
232
|
-
VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
564
|
+
VALUE field = rb_mysql_result_fetch_field(self, i, args->symbolizeKeys);
|
233
565
|
if (row[i]) {
|
234
566
|
VALUE val = Qnil;
|
235
567
|
enum enum_field_types type = fields[i].type;
|
236
568
|
|
237
|
-
if (!cast) {
|
569
|
+
if (!args->cast) {
|
238
570
|
if (type == MYSQL_TYPE_NULL) {
|
239
571
|
val = Qnil;
|
240
572
|
} else {
|
@@ -249,14 +581,14 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
249
581
|
val = Qnil;
|
250
582
|
break;
|
251
583
|
case MYSQL_TYPE_BIT: /* BIT field (MySQL 5.0.3 and up) */
|
252
|
-
if (castBool && fields[i].length == 1) {
|
584
|
+
if (args->castBool && fields[i].length == 1) {
|
253
585
|
val = *row[i] == 1 ? Qtrue : Qfalse;
|
254
586
|
}else{
|
255
587
|
val = rb_str_new(row[i], fieldLengths[i]);
|
256
588
|
}
|
257
589
|
break;
|
258
590
|
case MYSQL_TYPE_TINY: /* TINYINT field */
|
259
|
-
if (castBool && fields[i].length == 1) {
|
591
|
+
if (args->castBool && fields[i].length == 1) {
|
260
592
|
val = *row[i] != '0' ? Qtrue : Qfalse;
|
261
593
|
break;
|
262
594
|
}
|
@@ -299,9 +631,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
299
631
|
break;
|
300
632
|
}
|
301
633
|
msec = msec_char_to_uint(msec_char, sizeof(msec_char));
|
302
|
-
val = rb_funcall(rb_cTime, db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
303
|
-
if (!NIL_P(app_timezone)) {
|
304
|
-
if (app_timezone == intern_local) {
|
634
|
+
val = rb_funcall(rb_cTime, args->db_timezone, 7, opt_time_year, opt_time_month, opt_time_month, UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
635
|
+
if (!NIL_P(args->app_timezone)) {
|
636
|
+
if (args->app_timezone == intern_local) {
|
305
637
|
val = rb_funcall(val, intern_localtime, 0);
|
306
638
|
} else { /* utc */
|
307
639
|
val = rb_funcall(val, intern_utc, 0);
|
@@ -332,12 +664,12 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
332
664
|
} else {
|
333
665
|
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { /* use DateTime for larger date range, does not support microseconds */
|
334
666
|
VALUE offset = INT2NUM(0);
|
335
|
-
if (db_timezone == intern_local) {
|
667
|
+
if (args->db_timezone == intern_local) {
|
336
668
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
337
669
|
}
|
338
670
|
val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), offset);
|
339
|
-
if (!NIL_P(app_timezone)) {
|
340
|
-
if (app_timezone == intern_local) {
|
671
|
+
if (!NIL_P(args->app_timezone)) {
|
672
|
+
if (args->app_timezone == intern_local) {
|
341
673
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
342
674
|
val = rb_funcall(val, intern_new_offset, 1, offset);
|
343
675
|
} else { /* utc */
|
@@ -346,9 +678,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
346
678
|
}
|
347
679
|
} else {
|
348
680
|
msec = msec_char_to_uint(msec_char, sizeof(msec_char));
|
349
|
-
val = rb_funcall(rb_cTime, db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
350
|
-
if (!NIL_P(app_timezone)) {
|
351
|
-
if (app_timezone == intern_local) {
|
681
|
+
val = rb_funcall(rb_cTime, args->db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
682
|
+
if (!NIL_P(args->app_timezone)) {
|
683
|
+
if (args->app_timezone == intern_local) {
|
352
684
|
val = rb_funcall(val, intern_localtime, 0);
|
353
685
|
} else { /* utc */
|
354
686
|
val = rb_funcall(val, intern_utc, 0);
|
@@ -398,13 +730,13 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
398
730
|
break;
|
399
731
|
}
|
400
732
|
}
|
401
|
-
if (asArray) {
|
733
|
+
if (args->asArray) {
|
402
734
|
rb_ary_push(rowVal, val);
|
403
735
|
} else {
|
404
736
|
rb_hash_aset(rowVal, field, val);
|
405
737
|
}
|
406
738
|
} else {
|
407
|
-
if (asArray) {
|
739
|
+
if (args->asArray) {
|
408
740
|
rb_ary_push(rowVal, Qnil);
|
409
741
|
} else {
|
410
742
|
rb_hash_aset(rowVal, field, Qnil);
|
@@ -432,7 +764,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
432
764
|
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
433
765
|
}
|
434
766
|
|
435
|
-
if (RARRAY_LEN(wrapper->fields) != wrapper->numberOfFields) {
|
767
|
+
if ((unsigned)RARRAY_LEN(wrapper->fields) != wrapper->numberOfFields) {
|
436
768
|
for (i=0; i<wrapper->numberOfFields; i++) {
|
437
769
|
rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
438
770
|
}
|
@@ -441,55 +773,16 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
441
773
|
return wrapper->fields;
|
442
774
|
}
|
443
775
|
|
444
|
-
static VALUE
|
445
|
-
|
446
|
-
|
776
|
+
static VALUE rb_mysql_result_each_(VALUE self,
|
777
|
+
VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
|
778
|
+
const result_each_args *args)
|
779
|
+
{
|
447
780
|
unsigned long i;
|
448
|
-
const char *
|
449
|
-
|
450
|
-
MYSQL_FIELD * fields = NULL;
|
781
|
+
const char *errstr;
|
782
|
+
MYSQL_FIELD *fields = NULL;
|
451
783
|
|
452
784
|
GET_RESULT(self);
|
453
785
|
|
454
|
-
defaults = rb_iv_get(self, "@query_options");
|
455
|
-
Check_Type(defaults, T_HASH);
|
456
|
-
if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
|
457
|
-
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
458
|
-
} else {
|
459
|
-
opts = defaults;
|
460
|
-
}
|
461
|
-
|
462
|
-
symbolizeKeys = RTEST(rb_hash_aref(opts, sym_symbolize_keys));
|
463
|
-
asArray = rb_hash_aref(opts, sym_as) == sym_array;
|
464
|
-
castBool = RTEST(rb_hash_aref(opts, sym_cast_booleans));
|
465
|
-
cacheRows = RTEST(rb_hash_aref(opts, sym_cache_rows));
|
466
|
-
cast = RTEST(rb_hash_aref(opts, sym_cast));
|
467
|
-
|
468
|
-
if (wrapper->is_streaming && cacheRows) {
|
469
|
-
rb_warn(":cache_rows is ignored if :stream is true");
|
470
|
-
}
|
471
|
-
|
472
|
-
dbTz = rb_hash_aref(opts, sym_database_timezone);
|
473
|
-
if (dbTz == sym_local) {
|
474
|
-
db_timezone = intern_local;
|
475
|
-
} else if (dbTz == sym_utc) {
|
476
|
-
db_timezone = intern_utc;
|
477
|
-
} else {
|
478
|
-
if (!NIL_P(dbTz)) {
|
479
|
-
rb_warn(":database_timezone option must be :utc or :local - defaulting to :local");
|
480
|
-
}
|
481
|
-
db_timezone = intern_local;
|
482
|
-
}
|
483
|
-
|
484
|
-
appTz = rb_hash_aref(opts, sym_application_timezone);
|
485
|
-
if (appTz == sym_local) {
|
486
|
-
app_timezone = intern_local;
|
487
|
-
} else if (appTz == sym_utc) {
|
488
|
-
app_timezone = intern_utc;
|
489
|
-
} else {
|
490
|
-
app_timezone = Qnil;
|
491
|
-
}
|
492
|
-
|
493
786
|
if (wrapper->is_streaming) {
|
494
787
|
/* When streaming, we will only yield rows, not return them. */
|
495
788
|
if (wrapper->rows == Qnil) {
|
@@ -502,10 +795,10 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
502
795
|
fields = mysql_fetch_fields(wrapper->result);
|
503
796
|
|
504
797
|
do {
|
505
|
-
row =
|
798
|
+
row = fetch_row_func(self, fields, args);
|
506
799
|
if (row != Qnil) {
|
507
800
|
wrapper->numberOfRows++;
|
508
|
-
if (
|
801
|
+
if (args->block_given != Qnil) {
|
509
802
|
rb_yield(row);
|
510
803
|
}
|
511
804
|
}
|
@@ -524,20 +817,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
524
817
|
rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
|
525
818
|
}
|
526
819
|
} else {
|
527
|
-
if (wrapper->lastRowProcessed ==
|
528
|
-
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
|
529
|
-
if (wrapper->numberOfRows == 0) {
|
530
|
-
wrapper->rows = rb_ary_new();
|
531
|
-
return wrapper->rows;
|
532
|
-
}
|
533
|
-
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
534
|
-
} else if (!cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
535
|
-
mysql_data_seek(wrapper->result, 0);
|
536
|
-
wrapper->lastRowProcessed = 0;
|
537
|
-
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
538
|
-
}
|
539
|
-
|
540
|
-
if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
820
|
+
if (args->cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
541
821
|
/* we've already read the entire dataset from the C result into our */
|
542
822
|
/* internal array. Lets hand that over to the user since it's ready to go */
|
543
823
|
for (i = 0; i < wrapper->numberOfRows; i++) {
|
@@ -550,11 +830,11 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
550
830
|
|
551
831
|
for (i = 0; i < wrapper->numberOfRows; i++) {
|
552
832
|
VALUE row;
|
553
|
-
if (cacheRows && i < rowsProcessed) {
|
833
|
+
if (args->cacheRows && i < rowsProcessed) {
|
554
834
|
row = rb_ary_entry(wrapper->rows, i);
|
555
835
|
} else {
|
556
|
-
row =
|
557
|
-
if (cacheRows) {
|
836
|
+
row = fetch_row_func(self, fields, args);
|
837
|
+
if (args->cacheRows) {
|
558
838
|
rb_ary_store(wrapper->rows, i, row);
|
559
839
|
}
|
560
840
|
wrapper->lastRowProcessed++;
|
@@ -562,26 +842,109 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
562
842
|
|
563
843
|
if (row == Qnil) {
|
564
844
|
/* we don't need the mysql C dataset around anymore, peace it */
|
565
|
-
|
566
|
-
rb_mysql_result_free_result(wrapper);
|
567
|
-
}
|
845
|
+
rb_mysql_result_free_result(wrapper);
|
568
846
|
return Qnil;
|
569
847
|
}
|
570
848
|
|
571
|
-
if (
|
849
|
+
if (args->block_given != Qnil) {
|
572
850
|
rb_yield(row);
|
573
851
|
}
|
574
852
|
}
|
575
|
-
if (wrapper->lastRowProcessed == wrapper->numberOfRows
|
853
|
+
if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
576
854
|
/* we don't need the mysql C dataset around anymore, peace it */
|
577
855
|
rb_mysql_result_free_result(wrapper);
|
578
856
|
}
|
579
857
|
}
|
580
858
|
}
|
581
859
|
|
860
|
+
// FIXME return Enumerator instead?
|
861
|
+
// return rb_ary_each(wrapper->rows);
|
582
862
|
return wrapper->rows;
|
583
863
|
}
|
584
864
|
|
865
|
+
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
866
|
+
result_each_args args;
|
867
|
+
VALUE defaults, opts, block, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
|
868
|
+
ID db_timezone, app_timezone, dbTz, appTz;
|
869
|
+
int symbolizeKeys, asArray, castBool, cacheRows, cast;
|
870
|
+
|
871
|
+
GET_RESULT(self);
|
872
|
+
|
873
|
+
defaults = rb_iv_get(self, "@query_options");
|
874
|
+
Check_Type(defaults, T_HASH);
|
875
|
+
if (rb_scan_args(argc, argv, "01&", &opts, &block) == 1) {
|
876
|
+
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
877
|
+
} else {
|
878
|
+
opts = defaults;
|
879
|
+
}
|
880
|
+
|
881
|
+
symbolizeKeys = RTEST(rb_hash_aref(opts, sym_symbolize_keys));
|
882
|
+
asArray = rb_hash_aref(opts, sym_as) == sym_array;
|
883
|
+
castBool = RTEST(rb_hash_aref(opts, sym_cast_booleans));
|
884
|
+
cacheRows = RTEST(rb_hash_aref(opts, sym_cache_rows));
|
885
|
+
cast = RTEST(rb_hash_aref(opts, sym_cast));
|
886
|
+
|
887
|
+
if (wrapper->is_streaming && cacheRows) {
|
888
|
+
rb_warn(":cache_rows is ignored if :stream is true");
|
889
|
+
}
|
890
|
+
|
891
|
+
if (wrapper->stmt_wrapper && !cacheRows && !wrapper->is_streaming) {
|
892
|
+
rb_warn(":cache_rows is forced for prepared statements (if not streaming)");
|
893
|
+
}
|
894
|
+
|
895
|
+
if (wrapper->stmt_wrapper && !cast) {
|
896
|
+
rb_warn(":cast is forced for prepared statements");
|
897
|
+
}
|
898
|
+
|
899
|
+
dbTz = rb_hash_aref(opts, sym_database_timezone);
|
900
|
+
if (dbTz == sym_local) {
|
901
|
+
db_timezone = intern_local;
|
902
|
+
} else if (dbTz == sym_utc) {
|
903
|
+
db_timezone = intern_utc;
|
904
|
+
} else {
|
905
|
+
if (!NIL_P(dbTz)) {
|
906
|
+
rb_warn(":database_timezone option must be :utc or :local - defaulting to :local");
|
907
|
+
}
|
908
|
+
db_timezone = intern_local;
|
909
|
+
}
|
910
|
+
|
911
|
+
appTz = rb_hash_aref(opts, sym_application_timezone);
|
912
|
+
if (appTz == sym_local) {
|
913
|
+
app_timezone = intern_local;
|
914
|
+
} else if (appTz == sym_utc) {
|
915
|
+
app_timezone = intern_utc;
|
916
|
+
} else {
|
917
|
+
app_timezone = Qnil;
|
918
|
+
}
|
919
|
+
|
920
|
+
if (wrapper->lastRowProcessed == 0 && !wrapper->is_streaming) {
|
921
|
+
wrapper->numberOfRows = wrapper->stmt_wrapper ? mysql_stmt_num_rows(wrapper->stmt_wrapper->stmt) : mysql_num_rows(wrapper->result);
|
922
|
+
if (wrapper->numberOfRows == 0) {
|
923
|
+
wrapper->rows = rb_ary_new();
|
924
|
+
return wrapper->rows;
|
925
|
+
}
|
926
|
+
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
927
|
+
}
|
928
|
+
|
929
|
+
// Backward compat
|
930
|
+
args.symbolizeKeys = symbolizeKeys;
|
931
|
+
args.asArray = asArray;
|
932
|
+
args.castBool = castBool;
|
933
|
+
args.cacheRows = cacheRows;
|
934
|
+
args.cast = cast;
|
935
|
+
args.db_timezone = db_timezone;
|
936
|
+
args.app_timezone = app_timezone;
|
937
|
+
args.block_given = block;
|
938
|
+
|
939
|
+
if (wrapper->stmt_wrapper) {
|
940
|
+
fetch_row_func = rb_mysql_result_fetch_row_stmt;
|
941
|
+
} else {
|
942
|
+
fetch_row_func = rb_mysql_result_fetch_row;
|
943
|
+
}
|
944
|
+
|
945
|
+
return rb_mysql_result_each_(self, fetch_row_func, &args);
|
946
|
+
}
|
947
|
+
|
585
948
|
static VALUE rb_mysql_result_count(VALUE self) {
|
586
949
|
GET_RESULT(self);
|
587
950
|
|
@@ -595,12 +958,16 @@ static VALUE rb_mysql_result_count(VALUE self) {
|
|
595
958
|
return LONG2NUM(RARRAY_LEN(wrapper->rows));
|
596
959
|
} else {
|
597
960
|
/* MySQL returns an unsigned 64-bit long here */
|
598
|
-
|
961
|
+
if (wrapper->stmt_wrapper) {
|
962
|
+
return ULL2NUM(mysql_stmt_num_rows(wrapper->stmt_wrapper->stmt));
|
963
|
+
} else {
|
964
|
+
return ULL2NUM(mysql_num_rows(wrapper->result));
|
965
|
+
}
|
599
966
|
}
|
600
967
|
}
|
601
968
|
|
602
969
|
/* Mysql2::Result */
|
603
|
-
VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
|
970
|
+
VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r, VALUE statement) {
|
604
971
|
VALUE obj;
|
605
972
|
mysql2_result_wrapper * wrapper;
|
606
973
|
|
@@ -617,9 +984,21 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
617
984
|
wrapper->client = client;
|
618
985
|
wrapper->client_wrapper = DATA_PTR(client);
|
619
986
|
wrapper->client_wrapper->refcount++;
|
987
|
+
wrapper->result_buffers = NULL;
|
988
|
+
wrapper->is_null = NULL;
|
989
|
+
wrapper->error = NULL;
|
990
|
+
wrapper->length = NULL;
|
991
|
+
|
992
|
+
/* Keep a handle to the Statement to ensure it doesn't get garbage collected first */
|
993
|
+
wrapper->statement = statement;
|
994
|
+
if (statement != Qnil) {
|
995
|
+
wrapper->stmt_wrapper = DATA_PTR(statement);
|
996
|
+
wrapper->stmt_wrapper->refcount++;
|
997
|
+
} else {
|
998
|
+
wrapper->stmt_wrapper = NULL;
|
999
|
+
}
|
620
1000
|
|
621
1001
|
rb_obj_call_init(obj, 0, NULL);
|
622
|
-
|
623
1002
|
rb_iv_set(obj, "@query_options", options);
|
624
1003
|
|
625
1004
|
/* Options that cannot be changed in results.each(...) { |row| }
|