mysql2 0.2.24 → 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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1 -0
- data/LICENSE +21 -0
- data/README.md +237 -85
- data/ext/mysql2/client.c +582 -249
- data/ext/mysql2/client.h +10 -38
- data/ext/mysql2/extconf.rb +217 -66
- data/ext/mysql2/infile.c +2 -2
- data/ext/mysql2/mysql2_ext.c +9 -2
- data/ext/mysql2/mysql2_ext.h +13 -14
- data/ext/mysql2/mysql_enc_name_to_ruby.h +62 -58
- data/ext/mysql2/mysql_enc_to_ruby.h +82 -18
- data/ext/mysql2/result.c +736 -200
- data/ext/mysql2/result.h +13 -6
- data/ext/mysql2/statement.c +612 -0
- data/ext/mysql2/statement.h +17 -0
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +110 -28
- data/lib/mysql2/console.rb +1 -1
- data/lib/mysql2/em.rb +15 -9
- data/lib/mysql2/error.rb +57 -36
- data/lib/mysql2/field.rb +3 -0
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +9 -0
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +66 -15
- data/support/3A79BD29.asc +49 -0
- data/support/5072E1F5.asc +432 -0
- data/support/libmysql.def +219 -0
- data/support/mysql_enc_to_ruby.rb +15 -11
- data/support/ruby_enc_to_mysql.rb +8 -6
- metadata +30 -94
- data/MIT-LICENSE +0 -20
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +0 -635
- data/lib/arel/engines/sql/compilers/mysql2_compiler.rb +0 -11
- data/spec/configuration.yml.example +0 -17
- data/spec/em/em_spec.rb +0 -114
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -897
- data/spec/mysql2/error_spec.rb +0 -83
- data/spec/mysql2/result_spec.rb +0 -505
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -87
- data/spec/test_data +0 -1
data/ext/mysql2/result.c
CHANGED
@@ -1,64 +1,63 @@
|
|
1
1
|
#include <mysql2_ext.h>
|
2
2
|
|
3
|
-
#include <stdint.h>
|
4
|
-
|
5
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]))
|
6
5
|
|
7
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
8
6
|
static rb_encoding *binaryEncoding;
|
9
|
-
#endif
|
10
7
|
|
11
|
-
#if (SIZEOF_INT < SIZEOF_LONG) || defined(HAVE_RUBY_ENCODING_H)
|
12
8
|
/* on 64bit platforms we can handle dates way outside 2038-01-19T03:14:07
|
13
9
|
*
|
14
10
|
* (9999*31557600) + (12*2592000) + (31*86400) + (11*3600) + (59*60) + 59
|
15
11
|
*/
|
16
12
|
#define MYSQL2_MAX_TIME 315578267999ULL
|
17
|
-
#else
|
18
|
-
/**
|
19
|
-
* On 32bit platforms the maximum date the Time class can handle is 2038-01-19T03:14:07
|
20
|
-
* 2038 years + 1 month + 19 days + 3 hours + 14 minutes + 7 seconds = 64318634047 seconds
|
21
|
-
*
|
22
|
-
* (2038*31557600) + (1*2592000) + (19*86400) + (3*3600) + (14*60) + 7
|
23
|
-
*/
|
24
|
-
#define MYSQL2_MAX_TIME 64318634047ULL
|
25
|
-
#endif
|
26
13
|
|
27
|
-
#if defined(HAVE_RUBY_ENCODING_H)
|
28
14
|
/* 0000-1-1 00:00:00 UTC
|
29
15
|
*
|
30
16
|
* (0*31557600) + (1*2592000) + (1*86400) + (0*3600) + (0*60) + 0
|
31
17
|
*/
|
32
18
|
#define MYSQL2_MIN_TIME 2678400ULL
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
*
|
42
|
-
* (1901*31557600) + (12*2592000) + (13*86400) + (20*3600) + (45*60) + 52
|
43
|
-
*/
|
44
|
-
#define MYSQL2_MIN_TIME 60023299552ULL
|
45
|
-
#else
|
46
|
-
/* 1970-01-01 00:00:01 UTC : The Unix epoch - the oldest time in portable time_t.
|
47
|
-
*
|
48
|
-
* (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.
|
49
27
|
*/
|
50
|
-
#define
|
28
|
+
#define MYSQL2_BINARY_CHARSET 63
|
29
|
+
|
30
|
+
#ifndef MYSQL_TYPE_JSON
|
31
|
+
#define MYSQL_TYPE_JSON 245
|
51
32
|
#endif
|
52
33
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
34
|
+
#define GET_RESULT(self) \
|
35
|
+
mysql2_result_wrapper *wrapper; \
|
36
|
+
Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
|
37
|
+
|
38
|
+
typedef struct {
|
39
|
+
int symbolizeKeys;
|
40
|
+
int asArray;
|
41
|
+
int castBool;
|
42
|
+
int cacheRows;
|
43
|
+
int cast;
|
44
|
+
int streaming;
|
45
|
+
ID db_timezone;
|
46
|
+
ID app_timezone;
|
47
|
+
int block_given; /* boolean */
|
48
|
+
} result_each_args;
|
61
49
|
|
50
|
+
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
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;
|
59
|
+
|
60
|
+
/* Mark any VALUEs that are only referenced in C, so the GC won't get them. */
|
62
61
|
static void rb_mysql_result_mark(void * wrapper) {
|
63
62
|
mysql2_result_wrapper * w = wrapper;
|
64
63
|
if (w) {
|
@@ -66,13 +65,50 @@ static void rb_mysql_result_mark(void * wrapper) {
|
|
66
65
|
rb_gc_mark(w->rows);
|
67
66
|
rb_gc_mark(w->encoding);
|
68
67
|
rb_gc_mark(w->client);
|
68
|
+
rb_gc_mark(w->statement);
|
69
69
|
}
|
70
70
|
}
|
71
71
|
|
72
72
|
/* this may be called manually or during GC */
|
73
73
|
static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
|
74
|
-
if (wrapper
|
74
|
+
if (!wrapper) return;
|
75
|
+
|
76
|
+
if (wrapper->resultFreed != 1) {
|
77
|
+
if (wrapper->stmt_wrapper) {
|
78
|
+
if (!wrapper->stmt_wrapper->closed) {
|
79
|
+
mysql_stmt_free_result(wrapper->stmt_wrapper->stmt);
|
80
|
+
|
81
|
+
/* MySQL BUG? If the statement handle was previously used, and so
|
82
|
+
* mysql_stmt_bind_result was called, and if that result set and bind buffers were freed,
|
83
|
+
* MySQL still thinks the result set buffer is available and will prefetch the
|
84
|
+
* first result in mysql_stmt_execute. This will corrupt or crash the program.
|
85
|
+
* By setting bind_result_done back to 0, we make MySQL think that a result set
|
86
|
+
* has never been bound to this statement handle before to prevent the prefetch.
|
87
|
+
*/
|
88
|
+
wrapper->stmt_wrapper->stmt->bind_result_done = 0;
|
89
|
+
}
|
90
|
+
|
91
|
+
if (wrapper->statement != Qnil) {
|
92
|
+
decr_mysql2_stmt(wrapper->stmt_wrapper);
|
93
|
+
}
|
94
|
+
|
95
|
+
if (wrapper->result_buffers) {
|
96
|
+
unsigned int i;
|
97
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
98
|
+
if (wrapper->result_buffers[i].buffer) {
|
99
|
+
xfree(wrapper->result_buffers[i].buffer);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
xfree(wrapper->result_buffers);
|
103
|
+
xfree(wrapper->is_null);
|
104
|
+
xfree(wrapper->error);
|
105
|
+
xfree(wrapper->length);
|
106
|
+
}
|
107
|
+
/* Clue that the next statement execute will need to allocate a new result buffer. */
|
108
|
+
wrapper->result_buffers = NULL;
|
109
|
+
}
|
75
110
|
/* FIXME: this may call flush_use_result, which can hit the socket */
|
111
|
+
/* For prepared statements, wrapper->result is the result metadata */
|
76
112
|
mysql_free_result(wrapper->result);
|
77
113
|
wrapper->resultFreed = 1;
|
78
114
|
}
|
@@ -80,7 +116,7 @@ static void rb_mysql_result_free_result(mysql2_result_wrapper * wrapper) {
|
|
80
116
|
|
81
117
|
/* this is called during GC */
|
82
118
|
static void rb_mysql_result_free(void *ptr) {
|
83
|
-
mysql2_result_wrapper *
|
119
|
+
mysql2_result_wrapper *wrapper = ptr;
|
84
120
|
rb_mysql_result_free_result(wrapper);
|
85
121
|
|
86
122
|
// If the GC gets to client first it will be nil
|
@@ -91,6 +127,12 @@ static void rb_mysql_result_free(void *ptr) {
|
|
91
127
|
xfree(wrapper);
|
92
128
|
}
|
93
129
|
|
130
|
+
static VALUE rb_mysql_result_free_(VALUE self) {
|
131
|
+
GET_RESULT(self);
|
132
|
+
rb_mysql_result_free_result(wrapper);
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
|
94
136
|
/*
|
95
137
|
* for small results, this won't hit the network, but there's no
|
96
138
|
* reliable way for us to tell this so we'll always release the GVL
|
@@ -102,10 +144,16 @@ static void *nogvl_fetch_row(void *ptr) {
|
|
102
144
|
return mysql_fetch_row(result);
|
103
145
|
}
|
104
146
|
|
105
|
-
static
|
106
|
-
|
147
|
+
static void *nogvl_stmt_fetch(void *ptr) {
|
148
|
+
MYSQL_STMT *stmt = ptr;
|
149
|
+
uintptr_t r = mysql_stmt_fetch(stmt);
|
150
|
+
|
151
|
+
return (void *)r;
|
152
|
+
}
|
153
|
+
|
154
|
+
static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbolize_keys) {
|
107
155
|
VALUE rb_field;
|
108
|
-
|
156
|
+
GET_RESULT(self);
|
109
157
|
|
110
158
|
if (wrapper->fields == Qnil) {
|
111
159
|
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
@@ -115,28 +163,25 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
115
163
|
rb_field = rb_ary_entry(wrapper->fields, idx);
|
116
164
|
if (rb_field == Qnil) {
|
117
165
|
MYSQL_FIELD *field = NULL;
|
118
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
119
166
|
rb_encoding *default_internal_enc = rb_default_internal_encoding();
|
120
167
|
rb_encoding *conn_enc = rb_to_encoding(wrapper->encoding);
|
121
|
-
#endif
|
122
168
|
|
123
169
|
field = mysql_fetch_field_direct(wrapper->result, idx);
|
124
170
|
if (symbolize_keys) {
|
125
|
-
#ifdef HAVE_RB_INTERN3
|
126
171
|
rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
|
127
172
|
rb_field = ID2SYM(rb_field);
|
128
|
-
#else
|
129
|
-
VALUE colStr;
|
130
|
-
colStr = rb_str_new(field->name, field->name_length);
|
131
|
-
rb_field = ID2SYM(rb_to_id(colStr));
|
132
|
-
#endif
|
133
173
|
} else {
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
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) {
|
138
182
|
rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
|
139
183
|
}
|
184
|
+
rb_obj_freeze(rb_field);
|
140
185
|
#endif
|
141
186
|
}
|
142
187
|
rb_ary_store(wrapper->fields, idx, rb_field);
|
@@ -145,10 +190,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
145
190
|
return rb_field;
|
146
191
|
}
|
147
192
|
|
148
|
-
|
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
|
+
|
149
355
|
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
150
|
-
/* if binary flag is set, respect
|
151
|
-
if (field.flags & BINARY_FLAG && field.charsetnr ==
|
356
|
+
/* if binary flag is set, respect its wishes */
|
357
|
+
if (field.flags & BINARY_FLAG && field.charsetnr == MYSQL2_BINARY_CHARSET) {
|
152
358
|
rb_enc_associate(val, binaryEncoding);
|
153
359
|
} else if (!field.charsetnr) {
|
154
360
|
/* MySQL 4.x may not provide an encoding, binary will get the bytes through */
|
@@ -158,7 +364,8 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
158
364
|
const char *enc_name;
|
159
365
|
int enc_index;
|
160
366
|
|
161
|
-
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
|
+
|
162
369
|
if (enc_name != NULL) {
|
163
370
|
/* use the field encoding we were able to match */
|
164
371
|
enc_index = rb_enc_find_index(enc_name);
|
@@ -174,7 +381,6 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
174
381
|
}
|
175
382
|
return val;
|
176
383
|
}
|
177
|
-
#endif
|
178
384
|
|
179
385
|
/* Interpret microseconds digits left-aligned in fixed-width field.
|
180
386
|
* e.g. 10.123 seconds means 10 seconds and 123000 microseconds,
|
@@ -182,7 +388,7 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
182
388
|
*/
|
183
389
|
static unsigned int msec_char_to_uint(char *msec_char, size_t len)
|
184
390
|
{
|
185
|
-
|
391
|
+
size_t i;
|
186
392
|
for (i = 0; i < (len - 1); i++) {
|
187
393
|
if (msec_char[i] == '\0') {
|
188
394
|
msec_char[i] = '0';
|
@@ -191,23 +397,281 @@ static unsigned int msec_char_to_uint(char *msec_char, size_t len)
|
|
191
397
|
return (unsigned int)strtoul(msec_char, NULL, 10);
|
192
398
|
}
|
193
399
|
|
194
|
-
static
|
400
|
+
static void rb_mysql_result_alloc_result_buffers(VALUE self, MYSQL_FIELD *fields) {
|
401
|
+
unsigned int i;
|
402
|
+
GET_RESULT(self);
|
403
|
+
|
404
|
+
if (wrapper->result_buffers != NULL) return;
|
405
|
+
|
406
|
+
wrapper->result_buffers = xcalloc(wrapper->numberOfFields, sizeof(MYSQL_BIND));
|
407
|
+
wrapper->is_null = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
|
408
|
+
wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(my_bool));
|
409
|
+
wrapper->length = xcalloc(wrapper->numberOfFields, sizeof(unsigned long));
|
410
|
+
|
411
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
412
|
+
wrapper->result_buffers[i].buffer_type = fields[i].type;
|
413
|
+
|
414
|
+
// mysql type | C type
|
415
|
+
switch(fields[i].type) {
|
416
|
+
case MYSQL_TYPE_NULL: // NULL
|
417
|
+
break;
|
418
|
+
case MYSQL_TYPE_TINY: // signed char
|
419
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(signed char));
|
420
|
+
wrapper->result_buffers[i].buffer_length = sizeof(signed char);
|
421
|
+
break;
|
422
|
+
case MYSQL_TYPE_SHORT: // short int
|
423
|
+
case MYSQL_TYPE_YEAR: // short int
|
424
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(short int));
|
425
|
+
wrapper->result_buffers[i].buffer_length = sizeof(short int);
|
426
|
+
break;
|
427
|
+
case MYSQL_TYPE_INT24: // int
|
428
|
+
case MYSQL_TYPE_LONG: // int
|
429
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(int));
|
430
|
+
wrapper->result_buffers[i].buffer_length = sizeof(int);
|
431
|
+
break;
|
432
|
+
case MYSQL_TYPE_LONGLONG: // long long int
|
433
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(long long int));
|
434
|
+
wrapper->result_buffers[i].buffer_length = sizeof(long long int);
|
435
|
+
break;
|
436
|
+
case MYSQL_TYPE_FLOAT: // float
|
437
|
+
case MYSQL_TYPE_DOUBLE: // double
|
438
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(double));
|
439
|
+
wrapper->result_buffers[i].buffer_length = sizeof(double);
|
440
|
+
break;
|
441
|
+
case MYSQL_TYPE_TIME: // MYSQL_TIME
|
442
|
+
case MYSQL_TYPE_DATE: // MYSQL_TIME
|
443
|
+
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
|
444
|
+
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
|
445
|
+
case MYSQL_TYPE_TIMESTAMP: // MYSQL_TIME
|
446
|
+
wrapper->result_buffers[i].buffer = xcalloc(1, sizeof(MYSQL_TIME));
|
447
|
+
wrapper->result_buffers[i].buffer_length = sizeof(MYSQL_TIME);
|
448
|
+
break;
|
449
|
+
case MYSQL_TYPE_DECIMAL: // char[]
|
450
|
+
case MYSQL_TYPE_NEWDECIMAL: // char[]
|
451
|
+
case MYSQL_TYPE_STRING: // char[]
|
452
|
+
case MYSQL_TYPE_VAR_STRING: // char[]
|
453
|
+
case MYSQL_TYPE_VARCHAR: // char[]
|
454
|
+
case MYSQL_TYPE_TINY_BLOB: // char[]
|
455
|
+
case MYSQL_TYPE_BLOB: // char[]
|
456
|
+
case MYSQL_TYPE_MEDIUM_BLOB: // char[]
|
457
|
+
case MYSQL_TYPE_LONG_BLOB: // char[]
|
458
|
+
case MYSQL_TYPE_BIT: // char[]
|
459
|
+
case MYSQL_TYPE_SET: // char[]
|
460
|
+
case MYSQL_TYPE_ENUM: // char[]
|
461
|
+
case MYSQL_TYPE_GEOMETRY: // char[]
|
462
|
+
default:
|
463
|
+
wrapper->result_buffers[i].buffer = xmalloc(fields[i].max_length);
|
464
|
+
wrapper->result_buffers[i].buffer_length = fields[i].max_length;
|
465
|
+
break;
|
466
|
+
}
|
467
|
+
|
468
|
+
wrapper->result_buffers[i].is_null = &wrapper->is_null[i];
|
469
|
+
wrapper->result_buffers[i].length = &wrapper->length[i];
|
470
|
+
wrapper->result_buffers[i].error = &wrapper->error[i];
|
471
|
+
wrapper->result_buffers[i].is_unsigned = ((fields[i].flags & UNSIGNED_FLAG) != 0);
|
472
|
+
}
|
473
|
+
}
|
474
|
+
|
475
|
+
static VALUE rb_mysql_result_fetch_row_stmt(VALUE self, MYSQL_FIELD * fields, const result_each_args *args)
|
476
|
+
{
|
477
|
+
VALUE rowVal;
|
478
|
+
unsigned int i = 0;
|
479
|
+
|
480
|
+
rb_encoding *default_internal_enc;
|
481
|
+
rb_encoding *conn_enc;
|
482
|
+
GET_RESULT(self);
|
483
|
+
|
484
|
+
default_internal_enc = rb_default_internal_encoding();
|
485
|
+
conn_enc = rb_to_encoding(wrapper->encoding);
|
486
|
+
|
487
|
+
if (wrapper->fields == Qnil) {
|
488
|
+
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
489
|
+
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
490
|
+
}
|
491
|
+
if (args->asArray) {
|
492
|
+
rowVal = rb_ary_new2(wrapper->numberOfFields);
|
493
|
+
} else {
|
494
|
+
rowVal = rb_hash_new();
|
495
|
+
}
|
496
|
+
|
497
|
+
if (wrapper->result_buffers == NULL) {
|
498
|
+
rb_mysql_result_alloc_result_buffers(self, fields);
|
499
|
+
}
|
500
|
+
|
501
|
+
if (mysql_stmt_bind_result(wrapper->stmt_wrapper->stmt, wrapper->result_buffers)) {
|
502
|
+
rb_raise_mysql2_stmt_error(wrapper->stmt_wrapper);
|
503
|
+
}
|
504
|
+
|
505
|
+
{
|
506
|
+
switch((uintptr_t)rb_thread_call_without_gvl(nogvl_stmt_fetch, wrapper->stmt_wrapper->stmt, RUBY_UBF_IO, 0)) {
|
507
|
+
case 0:
|
508
|
+
/* success */
|
509
|
+
break;
|
510
|
+
|
511
|
+
case 1:
|
512
|
+
/* error */
|
513
|
+
rb_raise_mysql2_stmt_error(wrapper->stmt_wrapper);
|
514
|
+
|
515
|
+
case MYSQL_NO_DATA:
|
516
|
+
/* no more row */
|
517
|
+
return Qnil;
|
518
|
+
|
519
|
+
case MYSQL_DATA_TRUNCATED:
|
520
|
+
rb_raise(cMysql2Error, "IMPLBUG: caught MYSQL_DATA_TRUNCATED. should not come here as buffer_length is set to fields[i].max_length.");
|
521
|
+
}
|
522
|
+
}
|
523
|
+
|
524
|
+
for (i = 0; i < wrapper->numberOfFields; i++) {
|
525
|
+
VALUE field = rb_mysql_result_fetch_field(self, i, args->symbolizeKeys);
|
526
|
+
VALUE val = Qnil;
|
527
|
+
MYSQL_TIME *ts;
|
528
|
+
|
529
|
+
if (wrapper->is_null[i]) {
|
530
|
+
val = Qnil;
|
531
|
+
} else {
|
532
|
+
const MYSQL_BIND* const result_buffer = &wrapper->result_buffers[i];
|
533
|
+
|
534
|
+
switch(result_buffer->buffer_type) {
|
535
|
+
case MYSQL_TYPE_TINY: // signed char
|
536
|
+
if (args->castBool && fields[i].length == 1) {
|
537
|
+
val = (*((unsigned char*)result_buffer->buffer) != 0) ? Qtrue : Qfalse;
|
538
|
+
break;
|
539
|
+
}
|
540
|
+
if (result_buffer->is_unsigned) {
|
541
|
+
val = UINT2NUM(*((unsigned char*)result_buffer->buffer));
|
542
|
+
} else {
|
543
|
+
val = INT2NUM(*((signed char*)result_buffer->buffer));
|
544
|
+
}
|
545
|
+
break;
|
546
|
+
case MYSQL_TYPE_BIT: /* BIT field (MySQL 5.0.3 and up) */
|
547
|
+
if (args->castBool && fields[i].length == 1) {
|
548
|
+
val = (*((unsigned char*)result_buffer->buffer) != 0) ? Qtrue : Qfalse;
|
549
|
+
}else{
|
550
|
+
val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
|
551
|
+
}
|
552
|
+
break;
|
553
|
+
case MYSQL_TYPE_SHORT: // short int
|
554
|
+
case MYSQL_TYPE_YEAR: // short int
|
555
|
+
if (result_buffer->is_unsigned) {
|
556
|
+
val = UINT2NUM(*((unsigned short int*)result_buffer->buffer));
|
557
|
+
} else {
|
558
|
+
val = INT2NUM(*((short int*)result_buffer->buffer));
|
559
|
+
}
|
560
|
+
break;
|
561
|
+
case MYSQL_TYPE_INT24: // int
|
562
|
+
case MYSQL_TYPE_LONG: // int
|
563
|
+
if (result_buffer->is_unsigned) {
|
564
|
+
val = UINT2NUM(*((unsigned int*)result_buffer->buffer));
|
565
|
+
} else {
|
566
|
+
val = INT2NUM(*((int*)result_buffer->buffer));
|
567
|
+
}
|
568
|
+
break;
|
569
|
+
case MYSQL_TYPE_LONGLONG: // long long int
|
570
|
+
if (result_buffer->is_unsigned) {
|
571
|
+
val = ULL2NUM(*((unsigned long long int*)result_buffer->buffer));
|
572
|
+
} else {
|
573
|
+
val = LL2NUM(*((long long int*)result_buffer->buffer));
|
574
|
+
}
|
575
|
+
break;
|
576
|
+
case MYSQL_TYPE_FLOAT: // float
|
577
|
+
val = rb_float_new((double)(*((float*)result_buffer->buffer)));
|
578
|
+
break;
|
579
|
+
case MYSQL_TYPE_DOUBLE: // double
|
580
|
+
val = rb_float_new((double)(*((double*)result_buffer->buffer)));
|
581
|
+
break;
|
582
|
+
case MYSQL_TYPE_DATE: // MYSQL_TIME
|
583
|
+
case MYSQL_TYPE_NEWDATE: // MYSQL_TIME
|
584
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
585
|
+
val = rb_funcall(cDate, intern_new, 3, INT2NUM(ts->year), INT2NUM(ts->month), INT2NUM(ts->day));
|
586
|
+
break;
|
587
|
+
case MYSQL_TYPE_TIME: // MYSQL_TIME
|
588
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
589
|
+
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));
|
590
|
+
if (!NIL_P(args->app_timezone)) {
|
591
|
+
if (args->app_timezone == intern_local) {
|
592
|
+
val = rb_funcall(val, intern_localtime, 0);
|
593
|
+
} else { // utc
|
594
|
+
val = rb_funcall(val, intern_utc, 0);
|
595
|
+
}
|
596
|
+
}
|
597
|
+
break;
|
598
|
+
case MYSQL_TYPE_DATETIME: // MYSQL_TIME
|
599
|
+
case MYSQL_TYPE_TIMESTAMP: { // MYSQL_TIME
|
600
|
+
uint64_t seconds;
|
601
|
+
|
602
|
+
ts = (MYSQL_TIME*)result_buffer->buffer;
|
603
|
+
seconds = (ts->year*31557600ULL) + (ts->month*2592000ULL) + (ts->day*86400ULL) + (ts->hour*3600ULL) + (ts->minute*60ULL) + ts->second;
|
604
|
+
|
605
|
+
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { // use DateTime instead
|
606
|
+
VALUE offset = INT2NUM(0);
|
607
|
+
if (args->db_timezone == intern_local) {
|
608
|
+
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
609
|
+
}
|
610
|
+
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);
|
611
|
+
if (!NIL_P(args->app_timezone)) {
|
612
|
+
if (args->app_timezone == intern_local) {
|
613
|
+
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
614
|
+
val = rb_funcall(val, intern_new_offset, 1, offset);
|
615
|
+
} else { // utc
|
616
|
+
val = rb_funcall(val, intern_new_offset, 1, opt_utc_offset);
|
617
|
+
}
|
618
|
+
}
|
619
|
+
} else {
|
620
|
+
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));
|
621
|
+
if (!NIL_P(args->app_timezone)) {
|
622
|
+
if (args->app_timezone == intern_local) {
|
623
|
+
val = rb_funcall(val, intern_localtime, 0);
|
624
|
+
} else { // utc
|
625
|
+
val = rb_funcall(val, intern_utc, 0);
|
626
|
+
}
|
627
|
+
}
|
628
|
+
}
|
629
|
+
break;
|
630
|
+
}
|
631
|
+
case MYSQL_TYPE_DECIMAL: // char[]
|
632
|
+
case MYSQL_TYPE_NEWDECIMAL: // char[]
|
633
|
+
val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(result_buffer->buffer, *(result_buffer->length)));
|
634
|
+
break;
|
635
|
+
case MYSQL_TYPE_STRING: // char[]
|
636
|
+
case MYSQL_TYPE_VAR_STRING: // char[]
|
637
|
+
case MYSQL_TYPE_VARCHAR: // char[]
|
638
|
+
case MYSQL_TYPE_TINY_BLOB: // char[]
|
639
|
+
case MYSQL_TYPE_BLOB: // char[]
|
640
|
+
case MYSQL_TYPE_MEDIUM_BLOB: // char[]
|
641
|
+
case MYSQL_TYPE_LONG_BLOB: // char[]
|
642
|
+
case MYSQL_TYPE_SET: // char[]
|
643
|
+
case MYSQL_TYPE_ENUM: // char[]
|
644
|
+
case MYSQL_TYPE_GEOMETRY: // char[]
|
645
|
+
default:
|
646
|
+
val = rb_str_new(result_buffer->buffer, *(result_buffer->length));
|
647
|
+
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
648
|
+
break;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
if (args->asArray) {
|
653
|
+
rb_ary_push(rowVal, val);
|
654
|
+
} else {
|
655
|
+
rb_hash_aset(rowVal, field, val);
|
656
|
+
}
|
657
|
+
}
|
658
|
+
|
659
|
+
return rowVal;
|
660
|
+
}
|
661
|
+
|
662
|
+
static VALUE rb_mysql_result_fetch_row(VALUE self, MYSQL_FIELD * fields, const result_each_args *args)
|
663
|
+
{
|
195
664
|
VALUE rowVal;
|
196
|
-
mysql2_result_wrapper * wrapper;
|
197
665
|
MYSQL_ROW row;
|
198
666
|
unsigned int i = 0;
|
199
667
|
unsigned long * fieldLengths;
|
200
668
|
void * ptr;
|
201
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
202
669
|
rb_encoding *default_internal_enc;
|
203
670
|
rb_encoding *conn_enc;
|
204
|
-
|
205
|
-
GetMysql2Result(self, wrapper);
|
671
|
+
GET_RESULT(self);
|
206
672
|
|
207
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
208
673
|
default_internal_enc = rb_default_internal_encoding();
|
209
674
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
210
|
-
#endif
|
211
675
|
|
212
676
|
ptr = wrapper->result;
|
213
677
|
row = (MYSQL_ROW)rb_thread_call_without_gvl(nogvl_fetch_row, ptr, RUBY_UBF_IO, 0);
|
@@ -215,31 +679,29 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
215
679
|
return Qnil;
|
216
680
|
}
|
217
681
|
|
218
|
-
if (
|
682
|
+
if (wrapper->fields == Qnil) {
|
683
|
+
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
684
|
+
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
685
|
+
}
|
686
|
+
if (args->asArray) {
|
219
687
|
rowVal = rb_ary_new2(wrapper->numberOfFields);
|
220
688
|
} else {
|
221
689
|
rowVal = rb_hash_new();
|
222
690
|
}
|
223
691
|
fieldLengths = mysql_fetch_lengths(wrapper->result);
|
224
|
-
if (wrapper->fields == Qnil) {
|
225
|
-
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
226
|
-
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
227
|
-
}
|
228
692
|
|
229
693
|
for (i = 0; i < wrapper->numberOfFields; i++) {
|
230
|
-
VALUE field = rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
694
|
+
VALUE field = rb_mysql_result_fetch_field(self, i, args->symbolizeKeys);
|
231
695
|
if (row[i]) {
|
232
696
|
VALUE val = Qnil;
|
233
697
|
enum enum_field_types type = fields[i].type;
|
234
698
|
|
235
|
-
if(!cast) {
|
699
|
+
if (!args->cast) {
|
236
700
|
if (type == MYSQL_TYPE_NULL) {
|
237
701
|
val = Qnil;
|
238
702
|
} else {
|
239
703
|
val = rb_str_new(row[i], fieldLengths[i]);
|
240
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
241
704
|
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
242
|
-
#endif
|
243
705
|
}
|
244
706
|
} else {
|
245
707
|
switch(type) {
|
@@ -247,14 +709,14 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
247
709
|
val = Qnil;
|
248
710
|
break;
|
249
711
|
case MYSQL_TYPE_BIT: /* BIT field (MySQL 5.0.3 and up) */
|
250
|
-
if (castBool && fields[i].length == 1) {
|
712
|
+
if (args->castBool && fields[i].length == 1) {
|
251
713
|
val = *row[i] == 1 ? Qtrue : Qfalse;
|
252
714
|
}else{
|
253
715
|
val = rb_str_new(row[i], fieldLengths[i]);
|
254
716
|
}
|
255
717
|
break;
|
256
718
|
case MYSQL_TYPE_TINY: /* TINYINT field */
|
257
|
-
if (castBool && fields[i].length == 1) {
|
719
|
+
if (args->castBool && fields[i].length == 1) {
|
258
720
|
val = *row[i] != '0' ? Qtrue : Qfalse;
|
259
721
|
break;
|
260
722
|
}
|
@@ -270,9 +732,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
270
732
|
if (fields[i].decimals == 0) {
|
271
733
|
val = rb_cstr2inum(row[i], 10);
|
272
734
|
} else if (strtod(row[i], NULL) == 0.000000){
|
273
|
-
val = rb_funcall(
|
735
|
+
val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, opt_decimal_zero);
|
274
736
|
}else{
|
275
|
-
val = rb_funcall(
|
737
|
+
val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, rb_str_new(row[i], fieldLengths[i]));
|
276
738
|
}
|
277
739
|
break;
|
278
740
|
case MYSQL_TYPE_FLOAT: /* FLOAT field */
|
@@ -297,9 +759,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
297
759
|
break;
|
298
760
|
}
|
299
761
|
msec = msec_char_to_uint(msec_char, sizeof(msec_char));
|
300
|
-
val = rb_funcall(rb_cTime, db_timezone,
|
301
|
-
if (!NIL_P(app_timezone)) {
|
302
|
-
if (app_timezone == intern_local) {
|
762
|
+
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));
|
763
|
+
if (!NIL_P(args->app_timezone)) {
|
764
|
+
if (args->app_timezone == intern_local) {
|
303
765
|
val = rb_funcall(val, intern_localtime, 0);
|
304
766
|
} else { /* utc */
|
305
767
|
val = rb_funcall(val, intern_utc, 0);
|
@@ -330,12 +792,12 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
330
792
|
} else {
|
331
793
|
if (seconds < MYSQL2_MIN_TIME || seconds > MYSQL2_MAX_TIME) { /* use DateTime for larger date range, does not support microseconds */
|
332
794
|
VALUE offset = INT2NUM(0);
|
333
|
-
if (db_timezone == intern_local) {
|
795
|
+
if (args->db_timezone == intern_local) {
|
334
796
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
335
797
|
}
|
336
798
|
val = rb_funcall(cDateTime, intern_civil, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), offset);
|
337
|
-
if (!NIL_P(app_timezone)) {
|
338
|
-
if (app_timezone == intern_local) {
|
799
|
+
if (!NIL_P(args->app_timezone)) {
|
800
|
+
if (args->app_timezone == intern_local) {
|
339
801
|
offset = rb_funcall(cMysql2Client, intern_local_offset, 0);
|
340
802
|
val = rb_funcall(val, intern_new_offset, 1, offset);
|
341
803
|
} else { /* utc */
|
@@ -344,9 +806,9 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
344
806
|
}
|
345
807
|
} else {
|
346
808
|
msec = msec_char_to_uint(msec_char, sizeof(msec_char));
|
347
|
-
val = rb_funcall(rb_cTime, db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
348
|
-
if (!NIL_P(app_timezone)) {
|
349
|
-
if (app_timezone == intern_local) {
|
809
|
+
val = rb_funcall(rb_cTime, args->db_timezone, 7, UINT2NUM(year), UINT2NUM(month), UINT2NUM(day), UINT2NUM(hour), UINT2NUM(min), UINT2NUM(sec), UINT2NUM(msec));
|
810
|
+
if (!NIL_P(args->app_timezone)) {
|
811
|
+
if (args->app_timezone == intern_local) {
|
350
812
|
val = rb_funcall(val, intern_localtime, 0);
|
351
813
|
} else { /* utc */
|
352
814
|
val = rb_funcall(val, intern_utc, 0);
|
@@ -390,19 +852,17 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
390
852
|
case MYSQL_TYPE_GEOMETRY: /* Spatial fielda */
|
391
853
|
default:
|
392
854
|
val = rb_str_new(row[i], fieldLengths[i]);
|
393
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
394
855
|
val = mysql2_set_field_string_encoding(val, fields[i], default_internal_enc, conn_enc);
|
395
|
-
#endif
|
396
856
|
break;
|
397
857
|
}
|
398
858
|
}
|
399
|
-
if (asArray) {
|
859
|
+
if (args->asArray) {
|
400
860
|
rb_ary_push(rowVal, val);
|
401
861
|
} else {
|
402
862
|
rb_hash_aset(rowVal, field, val);
|
403
863
|
}
|
404
864
|
} else {
|
405
|
-
if (asArray) {
|
865
|
+
if (args->asArray) {
|
406
866
|
rb_ary_push(rowVal, Qnil);
|
407
867
|
} else {
|
408
868
|
rb_hash_aset(rowVal, field, Qnil);
|
@@ -413,14 +873,13 @@ static VALUE rb_mysql_result_fetch_row(VALUE self, ID db_timezone, ID app_timezo
|
|
413
873
|
}
|
414
874
|
|
415
875
|
static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
416
|
-
mysql2_result_wrapper * wrapper;
|
417
876
|
unsigned int i = 0;
|
418
877
|
short int symbolizeKeys = 0;
|
419
878
|
VALUE defaults;
|
420
879
|
|
421
|
-
|
880
|
+
GET_RESULT(self);
|
422
881
|
|
423
|
-
defaults =
|
882
|
+
defaults = rb_ivar_get(self, intern_query_options);
|
424
883
|
Check_Type(defaults, T_HASH);
|
425
884
|
if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
|
426
885
|
symbolizeKeys = 1;
|
@@ -431,7 +890,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
431
890
|
wrapper->fields = rb_ary_new2(wrapper->numberOfFields);
|
432
891
|
}
|
433
892
|
|
434
|
-
if (RARRAY_LEN(wrapper->fields) != wrapper->numberOfFields) {
|
893
|
+
if ((my_ulonglong)RARRAY_LEN(wrapper->fields) != wrapper->numberOfFields) {
|
435
894
|
for (i=0; i<wrapper->numberOfFields; i++) {
|
436
895
|
rb_mysql_result_fetch_field(self, i, symbolizeKeys);
|
437
896
|
}
|
@@ -440,108 +899,57 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
440
899
|
return wrapper->fields;
|
441
900
|
}
|
442
901
|
|
443
|
-
static VALUE
|
444
|
-
|
445
|
-
ID db_timezone, app_timezone, dbTz, appTz;
|
446
|
-
mysql2_result_wrapper * wrapper;
|
447
|
-
unsigned long i;
|
448
|
-
const char * errstr;
|
449
|
-
int symbolizeKeys = 0, asArray = 0, castBool = 0, cacheRows = 1, cast = 1, streaming = 0;
|
450
|
-
MYSQL_FIELD * fields = NULL;
|
451
|
-
|
452
|
-
GetMysql2Result(self, wrapper);
|
453
|
-
|
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
|
-
if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
|
463
|
-
symbolizeKeys = 1;
|
464
|
-
}
|
465
|
-
|
466
|
-
if (rb_hash_aref(opts, sym_as) == sym_array) {
|
467
|
-
asArray = 1;
|
468
|
-
}
|
902
|
+
static VALUE rb_mysql_result_fetch_field_types(VALUE self) {
|
903
|
+
unsigned int i = 0;
|
469
904
|
|
470
|
-
|
471
|
-
castBool = 1;
|
472
|
-
}
|
905
|
+
GET_RESULT(self);
|
473
906
|
|
474
|
-
if (
|
475
|
-
|
907
|
+
if (wrapper->fieldTypes == Qnil) {
|
908
|
+
wrapper->numberOfFields = mysql_num_fields(wrapper->result);
|
909
|
+
wrapper->fieldTypes = rb_ary_new2(wrapper->numberOfFields);
|
476
910
|
}
|
477
911
|
|
478
|
-
if (
|
479
|
-
|
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
|
+
}
|
480
916
|
}
|
481
917
|
|
482
|
-
|
483
|
-
|
484
|
-
}
|
918
|
+
return wrapper->fieldTypes;
|
919
|
+
}
|
485
920
|
|
486
|
-
|
487
|
-
|
488
|
-
|
921
|
+
static VALUE rb_mysql_result_each_(VALUE self,
|
922
|
+
VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
|
923
|
+
const result_each_args *args)
|
924
|
+
{
|
925
|
+
unsigned long i;
|
926
|
+
const char *errstr;
|
927
|
+
MYSQL_FIELD *fields = NULL;
|
489
928
|
|
490
|
-
|
491
|
-
if (dbTz == sym_local) {
|
492
|
-
db_timezone = intern_local;
|
493
|
-
} else if (dbTz == sym_utc) {
|
494
|
-
db_timezone = intern_utc;
|
495
|
-
} else {
|
496
|
-
if (!NIL_P(dbTz)) {
|
497
|
-
rb_warn(":database_timezone option must be :utc or :local - defaulting to :local");
|
498
|
-
}
|
499
|
-
db_timezone = intern_local;
|
500
|
-
}
|
929
|
+
GET_RESULT(self);
|
501
930
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
} else if (appTz == sym_utc) {
|
506
|
-
app_timezone = intern_utc;
|
507
|
-
} else {
|
508
|
-
app_timezone = Qnil;
|
509
|
-
}
|
510
|
-
|
511
|
-
if (wrapper->lastRowProcessed == 0) {
|
512
|
-
if (streaming) {
|
513
|
-
/* We can't get number of rows if we're streaming, */
|
514
|
-
/* until we've finished fetching all rows */
|
515
|
-
wrapper->numberOfRows = 0;
|
931
|
+
if (wrapper->is_streaming) {
|
932
|
+
/* When streaming, we will only yield rows, not return them. */
|
933
|
+
if (wrapper->rows == Qnil) {
|
516
934
|
wrapper->rows = rb_ary_new();
|
517
|
-
} else {
|
518
|
-
wrapper->numberOfRows = mysql_num_rows(wrapper->result);
|
519
|
-
if (wrapper->numberOfRows == 0) {
|
520
|
-
wrapper->rows = rb_ary_new();
|
521
|
-
return wrapper->rows;
|
522
|
-
}
|
523
|
-
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
524
935
|
}
|
525
|
-
}
|
526
936
|
|
527
|
-
if (streaming) {
|
528
937
|
if (!wrapper->streamingComplete) {
|
529
938
|
VALUE row;
|
530
939
|
|
531
940
|
fields = mysql_fetch_fields(wrapper->result);
|
532
941
|
|
533
942
|
do {
|
534
|
-
row =
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
943
|
+
row = fetch_row_func(self, fields, args);
|
944
|
+
if (row != Qnil) {
|
945
|
+
wrapper->numberOfRows++;
|
946
|
+
if (args->block_given) {
|
947
|
+
rb_yield(row);
|
948
|
+
}
|
539
949
|
}
|
540
950
|
} while(row != Qnil);
|
541
951
|
|
542
952
|
rb_mysql_result_free_result(wrapper);
|
543
|
-
|
544
|
-
wrapper->numberOfRows = wrapper->lastRowProcessed;
|
545
953
|
wrapper->streamingComplete = 1;
|
546
954
|
|
547
955
|
// Check for errors, the connection might have gone out from under us
|
@@ -554,7 +962,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
554
962
|
rb_raise(cMysql2Error, "You have already fetched all the rows for this query and streaming is true. (to reiterate you must requery).");
|
555
963
|
}
|
556
964
|
} else {
|
557
|
-
if (cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
965
|
+
if (args->cacheRows && wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
558
966
|
/* we've already read the entire dataset from the C result into our */
|
559
967
|
/* internal array. Lets hand that over to the user since it's ready to go */
|
560
968
|
for (i = 0; i < wrapper->numberOfRows; i++) {
|
@@ -567,11 +975,11 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
567
975
|
|
568
976
|
for (i = 0; i < wrapper->numberOfRows; i++) {
|
569
977
|
VALUE row;
|
570
|
-
if (cacheRows && i < rowsProcessed) {
|
978
|
+
if (args->cacheRows && i < rowsProcessed) {
|
571
979
|
row = rb_ary_entry(wrapper->rows, i);
|
572
980
|
} else {
|
573
|
-
row =
|
574
|
-
if (cacheRows) {
|
981
|
+
row = fetch_row_func(self, fields, args);
|
982
|
+
if (args->cacheRows) {
|
575
983
|
rb_ary_store(wrapper->rows, i, row);
|
576
984
|
}
|
577
985
|
wrapper->lastRowProcessed++;
|
@@ -579,43 +987,148 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
579
987
|
|
580
988
|
if (row == Qnil) {
|
581
989
|
/* we don't need the mysql C dataset around anymore, peace it */
|
582
|
-
|
990
|
+
if (args->cacheRows) {
|
991
|
+
rb_mysql_result_free_result(wrapper);
|
992
|
+
}
|
583
993
|
return Qnil;
|
584
994
|
}
|
585
995
|
|
586
|
-
if (
|
996
|
+
if (args->block_given) {
|
587
997
|
rb_yield(row);
|
588
998
|
}
|
589
999
|
}
|
590
|
-
if (wrapper->lastRowProcessed == wrapper->numberOfRows) {
|
1000
|
+
if (wrapper->lastRowProcessed == wrapper->numberOfRows && args->cacheRows) {
|
591
1001
|
/* we don't need the mysql C dataset around anymore, peace it */
|
592
1002
|
rb_mysql_result_free_result(wrapper);
|
593
1003
|
}
|
594
1004
|
}
|
595
1005
|
}
|
596
1006
|
|
1007
|
+
// FIXME return Enumerator instead?
|
1008
|
+
// return rb_ary_each(wrapper->rows);
|
597
1009
|
return wrapper->rows;
|
598
1010
|
}
|
599
1011
|
|
1012
|
+
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
1013
|
+
result_each_args args;
|
1014
|
+
VALUE defaults, opts, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
|
1015
|
+
ID db_timezone, app_timezone, dbTz, appTz;
|
1016
|
+
int symbolizeKeys, asArray, castBool, cacheRows, cast;
|
1017
|
+
|
1018
|
+
GET_RESULT(self);
|
1019
|
+
|
1020
|
+
if (wrapper->stmt_wrapper && wrapper->stmt_wrapper->closed) {
|
1021
|
+
rb_raise(cMysql2Error, "Statement handle already closed");
|
1022
|
+
}
|
1023
|
+
|
1024
|
+
defaults = rb_ivar_get(self, intern_query_options);
|
1025
|
+
Check_Type(defaults, T_HASH);
|
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) {
|
1030
|
+
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
1031
|
+
} else {
|
1032
|
+
opts = defaults;
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
symbolizeKeys = RTEST(rb_hash_aref(opts, sym_symbolize_keys));
|
1036
|
+
asArray = rb_hash_aref(opts, sym_as) == sym_array;
|
1037
|
+
castBool = RTEST(rb_hash_aref(opts, sym_cast_booleans));
|
1038
|
+
cacheRows = RTEST(rb_hash_aref(opts, sym_cache_rows));
|
1039
|
+
cast = RTEST(rb_hash_aref(opts, sym_cast));
|
1040
|
+
|
1041
|
+
if (wrapper->is_streaming && cacheRows) {
|
1042
|
+
rb_warn(":cache_rows is ignored if :stream is true");
|
1043
|
+
}
|
1044
|
+
|
1045
|
+
if (wrapper->stmt_wrapper && !cacheRows && !wrapper->is_streaming) {
|
1046
|
+
rb_warn(":cache_rows is forced for prepared statements (if not streaming)");
|
1047
|
+
cacheRows = 1;
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
if (wrapper->stmt_wrapper && !cast) {
|
1051
|
+
rb_warn(":cast is forced for prepared statements");
|
1052
|
+
}
|
1053
|
+
|
1054
|
+
dbTz = rb_hash_aref(opts, sym_database_timezone);
|
1055
|
+
if (dbTz == sym_local) {
|
1056
|
+
db_timezone = intern_local;
|
1057
|
+
} else if (dbTz == sym_utc) {
|
1058
|
+
db_timezone = intern_utc;
|
1059
|
+
} else {
|
1060
|
+
if (!NIL_P(dbTz)) {
|
1061
|
+
rb_warn(":database_timezone option must be :utc or :local - defaulting to :local");
|
1062
|
+
}
|
1063
|
+
db_timezone = intern_local;
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
appTz = rb_hash_aref(opts, sym_application_timezone);
|
1067
|
+
if (appTz == sym_local) {
|
1068
|
+
app_timezone = intern_local;
|
1069
|
+
} else if (appTz == sym_utc) {
|
1070
|
+
app_timezone = intern_utc;
|
1071
|
+
} else {
|
1072
|
+
app_timezone = Qnil;
|
1073
|
+
}
|
1074
|
+
|
1075
|
+
if (wrapper->rows == Qnil && !wrapper->is_streaming) {
|
1076
|
+
wrapper->numberOfRows = wrapper->stmt_wrapper ? mysql_stmt_num_rows(wrapper->stmt_wrapper->stmt) : mysql_num_rows(wrapper->result);
|
1077
|
+
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
1078
|
+
} else if (wrapper->rows && !cacheRows) {
|
1079
|
+
if (wrapper->resultFreed) {
|
1080
|
+
rb_raise(cMysql2Error, "Result set has already been freed");
|
1081
|
+
}
|
1082
|
+
mysql_data_seek(wrapper->result, 0);
|
1083
|
+
wrapper->lastRowProcessed = 0;
|
1084
|
+
wrapper->rows = rb_ary_new2(wrapper->numberOfRows);
|
1085
|
+
}
|
1086
|
+
|
1087
|
+
// Backward compat
|
1088
|
+
args.symbolizeKeys = symbolizeKeys;
|
1089
|
+
args.asArray = asArray;
|
1090
|
+
args.castBool = castBool;
|
1091
|
+
args.cacheRows = cacheRows;
|
1092
|
+
args.cast = cast;
|
1093
|
+
args.db_timezone = db_timezone;
|
1094
|
+
args.app_timezone = app_timezone;
|
1095
|
+
args.block_given = rb_block_given_p();
|
1096
|
+
|
1097
|
+
if (wrapper->stmt_wrapper) {
|
1098
|
+
fetch_row_func = rb_mysql_result_fetch_row_stmt;
|
1099
|
+
} else {
|
1100
|
+
fetch_row_func = rb_mysql_result_fetch_row;
|
1101
|
+
}
|
1102
|
+
|
1103
|
+
return rb_mysql_result_each_(self, fetch_row_func, &args);
|
1104
|
+
}
|
1105
|
+
|
600
1106
|
static VALUE rb_mysql_result_count(VALUE self) {
|
601
|
-
|
1107
|
+
GET_RESULT(self);
|
1108
|
+
|
1109
|
+
if (wrapper->is_streaming) {
|
1110
|
+
/* This is an unsigned long per result.h */
|
1111
|
+
return ULONG2NUM(wrapper->numberOfRows);
|
1112
|
+
}
|
602
1113
|
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
1114
|
+
if (wrapper->resultFreed) {
|
1115
|
+
/* Ruby arrays have platform signed long length */
|
1116
|
+
return LONG2NUM(RARRAY_LEN(wrapper->rows));
|
1117
|
+
} else {
|
1118
|
+
/* MySQL returns an unsigned 64-bit long here */
|
1119
|
+
if (wrapper->stmt_wrapper) {
|
1120
|
+
return ULL2NUM(mysql_stmt_num_rows(wrapper->stmt_wrapper->stmt));
|
607
1121
|
} else {
|
608
|
-
return
|
1122
|
+
return ULL2NUM(mysql_num_rows(wrapper->result));
|
609
1123
|
}
|
610
|
-
} else {
|
611
|
-
return INT2FIX(mysql_num_rows(wrapper->result));
|
612
1124
|
}
|
613
1125
|
}
|
614
1126
|
|
615
1127
|
/* Mysql2::Result */
|
616
|
-
VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r) {
|
1128
|
+
VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_RES *r, VALUE statement) {
|
617
1129
|
VALUE obj;
|
618
1130
|
mysql2_result_wrapper * wrapper;
|
1131
|
+
|
619
1132
|
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
|
620
1133
|
wrapper->numberOfFields = 0;
|
621
1134
|
wrapper->numberOfRows = 0;
|
@@ -623,28 +1136,51 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
623
1136
|
wrapper->resultFreed = 0;
|
624
1137
|
wrapper->result = r;
|
625
1138
|
wrapper->fields = Qnil;
|
1139
|
+
wrapper->fieldTypes = Qnil;
|
626
1140
|
wrapper->rows = Qnil;
|
627
1141
|
wrapper->encoding = encoding;
|
628
1142
|
wrapper->streamingComplete = 0;
|
629
1143
|
wrapper->client = client;
|
630
1144
|
wrapper->client_wrapper = DATA_PTR(client);
|
631
1145
|
wrapper->client_wrapper->refcount++;
|
1146
|
+
wrapper->result_buffers = NULL;
|
1147
|
+
wrapper->is_null = NULL;
|
1148
|
+
wrapper->error = NULL;
|
1149
|
+
wrapper->length = NULL;
|
1150
|
+
|
1151
|
+
/* Keep a handle to the Statement to ensure it doesn't get garbage collected first */
|
1152
|
+
wrapper->statement = statement;
|
1153
|
+
if (statement != Qnil) {
|
1154
|
+
wrapper->stmt_wrapper = DATA_PTR(statement);
|
1155
|
+
wrapper->stmt_wrapper->refcount++;
|
1156
|
+
} else {
|
1157
|
+
wrapper->stmt_wrapper = NULL;
|
1158
|
+
}
|
632
1159
|
|
633
1160
|
rb_obj_call_init(obj, 0, NULL);
|
1161
|
+
rb_ivar_set(obj, intern_query_options, options);
|
634
1162
|
|
635
|
-
|
1163
|
+
/* Options that cannot be changed in results.each(...) { |row| }
|
1164
|
+
* should be processed here. */
|
1165
|
+
wrapper->is_streaming = (rb_hash_aref(options, sym_stream) == Qtrue ? 1 : 0);
|
636
1166
|
|
637
1167
|
return obj;
|
638
1168
|
}
|
639
1169
|
|
640
1170
|
void init_mysql2_result() {
|
641
|
-
cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
642
1171
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
1172
|
+
rb_global_variable(&cDate);
|
643
1173
|
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
1174
|
+
rb_global_variable(&cDateTime);
|
644
1175
|
|
645
1176
|
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
|
1177
|
+
rb_undef_alloc_func(cMysql2Result);
|
1178
|
+
rb_global_variable(&cMysql2Result);
|
1179
|
+
|
646
1180
|
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
647
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);
|
1183
|
+
rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0);
|
648
1184
|
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
|
649
1185
|
rb_define_alias(cMysql2Result, "size", "count");
|
650
1186
|
|
@@ -656,6 +1192,8 @@ void init_mysql2_result() {
|
|
656
1192
|
intern_local_offset = rb_intern("local_offset");
|
657
1193
|
intern_civil = rb_intern("civil");
|
658
1194
|
intern_new_offset = rb_intern("new_offset");
|
1195
|
+
intern_BigDecimal = rb_intern("BigDecimal");
|
1196
|
+
intern_query_options = rb_intern("@query_options");
|
659
1197
|
|
660
1198
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
661
1199
|
sym_as = ID2SYM(rb_intern("as"));
|
@@ -678,7 +1216,5 @@ void init_mysql2_result() {
|
|
678
1216
|
opt_time_month = INT2NUM(1);
|
679
1217
|
opt_utc_offset = INT2NUM(0);
|
680
1218
|
|
681
|
-
#ifdef HAVE_RUBY_ENCODING_H
|
682
1219
|
binaryEncoding = rb_enc_find("binary");
|
683
|
-
#endif
|
684
1220
|
}
|