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.
- checksums.yaml +5 -5
- data/README.md +167 -48
- data/ext/mysql2/client.c +335 -108
- data/ext/mysql2/client.h +10 -41
- data/ext/mysql2/extconf.rb +84 -26
- data/ext/mysql2/mysql2_ext.c +8 -2
- data/ext/mysql2/mysql2_ext.h +21 -4
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -55
- data/ext/mysql2/mysql_enc_to_ruby.h +79 -3
- data/ext/mysql2/result.c +298 -92
- data/ext/mysql2/result.h +3 -3
- data/ext/mysql2/statement.c +137 -81
- data/ext/mysql2/statement.h +0 -2
- data/ext/mysql2/wait_for_single_fd.h +2 -1
- data/lib/mysql2/client.rb +55 -28
- data/lib/mysql2/em.rb +2 -4
- data/lib/mysql2/error.rb +52 -22
- data/lib/mysql2/result.rb +2 -0
- data/lib/mysql2/statement.rb +3 -11
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +19 -15
- data/support/3A79BD29.asc +49 -0
- data/support/5072E1F5.asc +5 -5
- data/support/C74CD1D8.asc +104 -0
- data/support/mysql_enc_to_ruby.rb +9 -3
- data/support/ruby_enc_to_mysql.rb +8 -5
- metadata +19 -62
- data/examples/eventmachine.rb +0 -21
- data/examples/threaded.rb +0 -18
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -136
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1039
- data/spec/mysql2/error_spec.rb +0 -82
- data/spec/mysql2/result_spec.rb +0 -545
- data/spec/mysql2/statement_spec.rb +0 -776
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -108
- data/spec/ssl/ca-cert.pem +0 -17
- data/spec/ssl/ca-key.pem +0 -27
- data/spec/ssl/ca.cnf +0 -22
- data/spec/ssl/cert.cnf +0 -22
- data/spec/ssl/client-cert.pem +0 -17
- data/spec/ssl/client-key.pem +0 -27
- data/spec/ssl/client-req.pem +0 -15
- data/spec/ssl/gen_certs.sh +0 -48
- data/spec/ssl/pkcs8-client-key.pem +0 -28
- data/spec/ssl/pkcs8-server-key.pem +0 -28
- data/spec/ssl/server-cert.pem +0 -17
- data/spec/ssl/server-key.pem +0 -27
- data/spec/ssl/server-req.pem +0 -15
- 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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
72
|
-
static VALUE
|
73
|
-
|
74
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
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
|
-
|
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 ==
|
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(
|
266
|
-
wrapper->error = xcalloc(wrapper->numberOfFields, sizeof(
|
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(
|
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(
|
781
|
+
val = rb_funcall(rb_mKernel, intern_BigDecimal, 1, opt_decimal_zero);
|
606
782
|
}else{
|
607
|
-
val = rb_funcall(
|
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 =
|
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
|
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
|
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,
|
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 =
|
1070
|
+
defaults = rb_ivar_get(self, intern_query_options);
|
878
1071
|
Check_Type(defaults, T_HASH);
|
879
|
-
|
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 =
|
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
|
-
|
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
|
-
|
26
|
-
|
25
|
+
my_bool *is_null;
|
26
|
+
my_bool *error;
|
27
27
|
unsigned long *length;
|
28
28
|
} mysql2_result_wrapper;
|
29
29
|
|