mysql2 0.5.2 → 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 +145 -44
- data/ext/mysql2/client.c +236 -58
- data/ext/mysql2/client.h +9 -2
- data/ext/mysql2/extconf.rb +62 -7
- data/ext/mysql2/mysql2_ext.c +6 -1
- data/ext/mysql2/mysql2_ext.h +13 -0
- data/ext/mysql2/mysql_enc_name_to_ruby.h +60 -55
- data/ext/mysql2/mysql_enc_to_ruby.h +71 -5
- data/ext/mysql2/result.c +287 -22
- data/ext/mysql2/result.h +1 -0
- data/ext/mysql2/statement.c +63 -14
- data/lib/mysql2/client.rb +24 -3
- data/lib/mysql2/error.rb +4 -3
- data/lib/mysql2/statement.rb +1 -3
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +8 -3
- 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 +7 -1
- data/support/ruby_enc_to_mysql.rb +3 -0
- metadata +15 -59
- data/examples/eventmachine.rb +0 -19
- data/examples/threaded.rb +0 -16
- data/spec/configuration.yml.example +0 -11
- data/spec/em/em_spec.rb +0 -135
- data/spec/my.cnf.example +0 -9
- data/spec/mysql2/client_spec.rb +0 -1072
- data/spec/mysql2/error_spec.rb +0 -78
- data/spec/mysql2/result_spec.rb +0 -485
- data/spec/mysql2/statement_spec.rb +0 -712
- data/spec/rcov.opts +0 -3
- data/spec/spec_helper.rb +0 -112
- 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,6 +1,7 @@
|
|
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
6
|
static rb_encoding *binaryEncoding;
|
6
7
|
|
@@ -16,9 +17,27 @@ static rb_encoding *binaryEncoding;
|
|
16
17
|
*/
|
17
18
|
#define MYSQL2_MIN_TIME 2678400ULL
|
18
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.
|
27
|
+
*/
|
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)
|
36
|
+
#endif
|
37
|
+
|
19
38
|
#define GET_RESULT(self) \
|
20
39
|
mysql2_result_wrapper *wrapper; \
|
21
|
-
|
40
|
+
TypedData_Get_Struct(self, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
|
22
41
|
|
23
42
|
typedef struct {
|
24
43
|
int symbolizeKeys;
|
@@ -29,14 +48,15 @@ typedef struct {
|
|
29
48
|
int streaming;
|
30
49
|
ID db_timezone;
|
31
50
|
ID app_timezone;
|
32
|
-
|
51
|
+
int block_given; /* boolean */
|
33
52
|
} result_each_args;
|
34
53
|
|
35
54
|
extern VALUE mMysql2, cMysql2Client, cMysql2Error;
|
36
55
|
static VALUE cMysql2Result, cDateTime, cDate;
|
37
56
|
static VALUE opt_decimal_zero, opt_float_zero, opt_time_year, opt_time_month, opt_utc_offset;
|
38
57
|
static ID intern_new, intern_utc, intern_local, intern_localtime, intern_local_offset,
|
39
|
-
intern_civil, intern_new_offset, intern_merge, intern_BigDecimal
|
58
|
+
intern_civil, intern_new_offset, intern_merge, intern_BigDecimal,
|
59
|
+
intern_query_options;
|
40
60
|
static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
|
41
61
|
sym_application_timezone, sym_local, sym_utc, sym_cast_booleans,
|
42
62
|
sym_cache_rows, sym_cast, sym_stream, sym_name;
|
@@ -45,11 +65,11 @@ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
|
|
45
65
|
static void rb_mysql_result_mark(void * wrapper) {
|
46
66
|
mysql2_result_wrapper * w = wrapper;
|
47
67
|
if (w) {
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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);
|
53
73
|
}
|
54
74
|
}
|
55
75
|
|
@@ -111,6 +131,48 @@ static void rb_mysql_result_free(void *ptr) {
|
|
111
131
|
xfree(wrapper);
|
112
132
|
}
|
113
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
|
+
|
114
176
|
static VALUE rb_mysql_result_free_(VALUE self) {
|
115
177
|
GET_RESULT(self);
|
116
178
|
rb_mysql_result_free_result(wrapper);
|
@@ -155,11 +217,18 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
|
|
155
217
|
rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
|
156
218
|
rb_field = ID2SYM(rb_field);
|
157
219
|
} else {
|
158
|
-
|
159
|
-
|
160
|
-
if (default_internal_enc) {
|
220
|
+
#ifdef HAVE_RB_ENC_INTERNED_STR
|
221
|
+
rb_field = rb_enc_interned_str(field->name, field->name_length, conn_enc);
|
222
|
+
if (default_internal_enc && default_internal_enc != conn_enc) {
|
223
|
+
rb_field = rb_str_to_interned_str(rb_str_export_to_enc(rb_field, default_internal_enc));
|
224
|
+
}
|
225
|
+
#else
|
226
|
+
rb_field = rb_enc_str_new(field->name, field->name_length, conn_enc);
|
227
|
+
if (default_internal_enc && default_internal_enc != conn_enc) {
|
161
228
|
rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
|
162
229
|
}
|
230
|
+
rb_obj_freeze(rb_field);
|
231
|
+
#endif
|
163
232
|
}
|
164
233
|
rb_ary_store(wrapper->fields, idx, rb_field);
|
165
234
|
}
|
@@ -167,9 +236,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
|
|
167
236
|
return rb_field;
|
168
237
|
}
|
169
238
|
|
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
|
+
|
170
401
|
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
171
402
|
/* if binary flag is set, respect its wishes */
|
172
|
-
if (field.flags & BINARY_FLAG && field.charsetnr ==
|
403
|
+
if (field.flags & BINARY_FLAG && field.charsetnr == MYSQL2_BINARY_CHARSET) {
|
173
404
|
rb_enc_associate(val, binaryEncoding);
|
174
405
|
} else if (!field.charsetnr) {
|
175
406
|
/* MySQL 4.x may not provide an encoding, binary will get the bytes through */
|
@@ -179,8 +410,8 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
179
410
|
const char *enc_name;
|
180
411
|
int enc_index;
|
181
412
|
|
182
|
-
enc_name = (field.charsetnr-1 <
|
183
|
-
|
413
|
+
enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
|
414
|
+
|
184
415
|
if (enc_name != NULL) {
|
185
416
|
/* use the field encoding we were able to match */
|
186
417
|
enc_index = rb_enc_find_index(enc_name);
|
@@ -694,7 +925,7 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
694
925
|
|
695
926
|
GET_RESULT(self);
|
696
927
|
|
697
|
-
defaults =
|
928
|
+
defaults = rb_ivar_get(self, intern_query_options);
|
698
929
|
Check_Type(defaults, T_HASH);
|
699
930
|
if (rb_hash_aref(defaults, sym_symbolize_keys) == Qtrue) {
|
700
931
|
symbolizeKeys = 1;
|
@@ -714,6 +945,25 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
714
945
|
return wrapper->fields;
|
715
946
|
}
|
716
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
|
+
|
717
967
|
static VALUE rb_mysql_result_each_(VALUE self,
|
718
968
|
VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
|
719
969
|
const result_each_args *args)
|
@@ -739,7 +989,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
|
|
739
989
|
row = fetch_row_func(self, fields, args);
|
740
990
|
if (row != Qnil) {
|
741
991
|
wrapper->numberOfRows++;
|
742
|
-
if (args->block_given
|
992
|
+
if (args->block_given) {
|
743
993
|
rb_yield(row);
|
744
994
|
}
|
745
995
|
}
|
@@ -789,7 +1039,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
|
|
789
1039
|
return Qnil;
|
790
1040
|
}
|
791
1041
|
|
792
|
-
if (args->block_given
|
1042
|
+
if (args->block_given) {
|
793
1043
|
rb_yield(row);
|
794
1044
|
}
|
795
1045
|
}
|
@@ -807,7 +1057,7 @@ static VALUE rb_mysql_result_each_(VALUE self,
|
|
807
1057
|
|
808
1058
|
static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
809
1059
|
result_each_args args;
|
810
|
-
VALUE defaults, opts,
|
1060
|
+
VALUE defaults, opts, (*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args);
|
811
1061
|
ID db_timezone, app_timezone, dbTz, appTz;
|
812
1062
|
int symbolizeKeys, asArray, castBool, cacheRows, cast;
|
813
1063
|
|
@@ -817,9 +1067,12 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
817
1067
|
rb_raise(cMysql2Error, "Statement handle already closed");
|
818
1068
|
}
|
819
1069
|
|
820
|
-
defaults =
|
1070
|
+
defaults = rb_ivar_get(self, intern_query_options);
|
821
1071
|
Check_Type(defaults, T_HASH);
|
822
|
-
|
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) {
|
823
1076
|
opts = rb_funcall(defaults, intern_merge, 1, opts);
|
824
1077
|
} else {
|
825
1078
|
opts = defaults;
|
@@ -885,7 +1138,7 @@ static VALUE rb_mysql_result_each(int argc, VALUE * argv, VALUE self) {
|
|
885
1138
|
args.cast = cast;
|
886
1139
|
args.db_timezone = db_timezone;
|
887
1140
|
args.app_timezone = app_timezone;
|
888
|
-
args.block_given =
|
1141
|
+
args.block_given = rb_block_given_p();
|
889
1142
|
|
890
1143
|
if (wrapper->stmt_wrapper) {
|
891
1144
|
fetch_row_func = rb_mysql_result_fetch_row_stmt;
|
@@ -922,13 +1175,18 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
922
1175
|
VALUE obj;
|
923
1176
|
mysql2_result_wrapper * wrapper;
|
924
1177
|
|
1178
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
1179
|
+
obj = TypedData_Make_Struct(cMysql2Result, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
|
1180
|
+
#else
|
925
1181
|
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
|
1182
|
+
#endif
|
926
1183
|
wrapper->numberOfFields = 0;
|
927
1184
|
wrapper->numberOfRows = 0;
|
928
1185
|
wrapper->lastRowProcessed = 0;
|
929
1186
|
wrapper->resultFreed = 0;
|
930
1187
|
wrapper->result = r;
|
931
1188
|
wrapper->fields = Qnil;
|
1189
|
+
wrapper->fieldTypes = Qnil;
|
932
1190
|
wrapper->rows = Qnil;
|
933
1191
|
wrapper->encoding = encoding;
|
934
1192
|
wrapper->streamingComplete = 0;
|
@@ -950,7 +1208,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
950
1208
|
}
|
951
1209
|
|
952
1210
|
rb_obj_call_init(obj, 0, NULL);
|
953
|
-
|
1211
|
+
rb_ivar_set(obj, intern_query_options, options);
|
954
1212
|
|
955
1213
|
/* Options that cannot be changed in results.each(...) { |row| }
|
956
1214
|
* should be processed here. */
|
@@ -961,11 +1219,17 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
961
1219
|
|
962
1220
|
void init_mysql2_result() {
|
963
1221
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
1222
|
+
rb_global_variable(&cDate);
|
964
1223
|
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
1224
|
+
rb_global_variable(&cDateTime);
|
965
1225
|
|
966
1226
|
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
|
1227
|
+
rb_undef_alloc_func(cMysql2Result);
|
1228
|
+
rb_global_variable(&cMysql2Result);
|
1229
|
+
|
967
1230
|
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
968
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);
|
969
1233
|
rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0);
|
970
1234
|
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
|
971
1235
|
rb_define_alias(cMysql2Result, "size", "count");
|
@@ -979,6 +1243,7 @@ void init_mysql2_result() {
|
|
979
1243
|
intern_civil = rb_intern("civil");
|
980
1244
|
intern_new_offset = rb_intern("new_offset");
|
981
1245
|
intern_BigDecimal = rb_intern("BigDecimal");
|
1246
|
+
intern_query_options = rb_intern("@query_options");
|
982
1247
|
|
983
1248
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
984
1249
|
sym_as = ID2SYM(rb_intern("as"));
|
data/ext/mysql2/result.h
CHANGED
data/ext/mysql2/statement.c
CHANGED
@@ -3,11 +3,16 @@
|
|
3
3
|
extern VALUE mMysql2, cMysql2Error;
|
4
4
|
static VALUE cMysql2Statement, cBigDecimal, cDateTime, cDate;
|
5
5
|
static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s, intern_merge_bang;
|
6
|
-
static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year
|
6
|
+
static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year,
|
7
|
+
intern_query_options;
|
8
|
+
|
9
|
+
#ifndef NEW_TYPEDDATA_WRAPPER
|
10
|
+
#define TypedData_Get_Struct(obj, type, ignore, sval) Data_Get_Struct(obj, type, sval)
|
11
|
+
#endif
|
7
12
|
|
8
13
|
#define GET_STATEMENT(self) \
|
9
14
|
mysql_stmt_wrapper *stmt_wrapper; \
|
10
|
-
|
15
|
+
TypedData_Get_Struct(self, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper); \
|
11
16
|
if (!stmt_wrapper->stmt) { rb_raise(cMysql2Error, "Invalid statement handle"); } \
|
12
17
|
if (stmt_wrapper->closed) { rb_raise(cMysql2Error, "Statement handle already closed"); }
|
13
18
|
|
@@ -15,9 +20,45 @@ static void rb_mysql_stmt_mark(void * ptr) {
|
|
15
20
|
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
16
21
|
if (!stmt_wrapper) return;
|
17
22
|
|
18
|
-
|
23
|
+
rb_gc_mark_movable(stmt_wrapper->client);
|
24
|
+
}
|
25
|
+
|
26
|
+
static void rb_mysql_stmt_free(void *ptr) {
|
27
|
+
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
28
|
+
decr_mysql2_stmt(stmt_wrapper);
|
19
29
|
}
|
20
30
|
|
31
|
+
static size_t rb_mysql_stmt_memsize(const void * ptr) {
|
32
|
+
const mysql_stmt_wrapper *stmt_wrapper = ptr;
|
33
|
+
return sizeof(*stmt_wrapper);
|
34
|
+
}
|
35
|
+
|
36
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
37
|
+
static void rb_mysql_stmt_compact(void * ptr) {
|
38
|
+
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
39
|
+
if (!stmt_wrapper) return;
|
40
|
+
|
41
|
+
rb_mysql2_gc_location(stmt_wrapper->client);
|
42
|
+
}
|
43
|
+
#endif
|
44
|
+
|
45
|
+
static const rb_data_type_t rb_mysql_statement_type = {
|
46
|
+
"rb_mysql_statement",
|
47
|
+
{
|
48
|
+
rb_mysql_stmt_mark,
|
49
|
+
rb_mysql_stmt_free,
|
50
|
+
rb_mysql_stmt_memsize,
|
51
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
52
|
+
rb_mysql_stmt_compact,
|
53
|
+
#endif
|
54
|
+
},
|
55
|
+
0,
|
56
|
+
0,
|
57
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
58
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
59
|
+
#endif
|
60
|
+
};
|
61
|
+
|
21
62
|
static void *nogvl_stmt_close(void *ptr) {
|
22
63
|
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
23
64
|
if (stmt_wrapper->stmt) {
|
@@ -27,11 +68,6 @@ static void *nogvl_stmt_close(void *ptr) {
|
|
27
68
|
return NULL;
|
28
69
|
}
|
29
70
|
|
30
|
-
static void rb_mysql_stmt_free(void *ptr) {
|
31
|
-
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
32
|
-
decr_mysql2_stmt(stmt_wrapper);
|
33
|
-
}
|
34
|
-
|
35
71
|
void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper) {
|
36
72
|
stmt_wrapper->refcount--;
|
37
73
|
|
@@ -45,7 +81,7 @@ void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) {
|
|
45
81
|
VALUE e;
|
46
82
|
GET_CLIENT(stmt_wrapper->client);
|
47
83
|
VALUE rb_error_msg = rb_str_new2(mysql_stmt_error(stmt_wrapper->stmt));
|
48
|
-
VALUE rb_sql_state =
|
84
|
+
VALUE rb_sql_state = rb_str_new2(mysql_stmt_sqlstate(stmt_wrapper->stmt));
|
49
85
|
|
50
86
|
rb_encoding *conn_enc;
|
51
87
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
@@ -95,7 +131,11 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
|
|
95
131
|
|
96
132
|
Check_Type(sql, T_STRING);
|
97
133
|
|
134
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
135
|
+
rb_stmt = TypedData_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper);
|
136
|
+
#else
|
98
137
|
rb_stmt = Data_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, rb_mysql_stmt_mark, rb_mysql_stmt_free, stmt_wrapper);
|
138
|
+
#endif
|
99
139
|
{
|
100
140
|
stmt_wrapper->client = rb_client;
|
101
141
|
stmt_wrapper->refcount = 1;
|
@@ -404,7 +444,7 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
|
|
404
444
|
}
|
405
445
|
|
406
446
|
// Duplicate the options hash, merge! extra opts, put the copy into the Result object
|
407
|
-
current = rb_hash_dup(
|
447
|
+
current = rb_hash_dup(rb_ivar_get(stmt_wrapper->client, intern_query_options));
|
408
448
|
(void)RB_GC_GUARD(current);
|
409
449
|
Check_Type(current, T_HASH);
|
410
450
|
|
@@ -447,7 +487,7 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
|
|
447
487
|
if (metadata == NULL) {
|
448
488
|
if (mysql_stmt_errno(stmt) != 0) {
|
449
489
|
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
|
450
|
-
wrapper->
|
490
|
+
wrapper->active_fiber = Qnil;
|
451
491
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
452
492
|
}
|
453
493
|
// no data and no error, so query was not a SELECT
|
@@ -455,12 +495,12 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
|
|
455
495
|
}
|
456
496
|
|
457
497
|
if (!is_streaming) {
|
458
|
-
//
|
498
|
+
// receive the whole result set from the server
|
459
499
|
if (mysql_stmt_store_result(stmt)) {
|
460
500
|
mysql_free_result(metadata);
|
461
501
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
462
502
|
}
|
463
|
-
wrapper->
|
503
|
+
wrapper->active_fiber = Qnil;
|
464
504
|
}
|
465
505
|
|
466
506
|
resultObj = rb_mysql_result_to_obj(stmt_wrapper->client, wrapper->encoding, current, metadata, self);
|
@@ -501,7 +541,7 @@ static VALUE rb_mysql_stmt_fields(VALUE self) {
|
|
501
541
|
if (metadata == NULL) {
|
502
542
|
if (mysql_stmt_errno(stmt) != 0) {
|
503
543
|
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
|
504
|
-
wrapper->
|
544
|
+
wrapper->active_fiber = Qnil;
|
505
545
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
506
546
|
}
|
507
547
|
// no data and no error, so query was not a SELECT
|
@@ -571,10 +611,18 @@ static VALUE rb_mysql_stmt_close(VALUE self) {
|
|
571
611
|
|
572
612
|
void init_mysql2_statement() {
|
573
613
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
614
|
+
rb_global_variable(&cDate);
|
615
|
+
|
574
616
|
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
617
|
+
rb_global_variable(&cDateTime);
|
618
|
+
|
575
619
|
cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
620
|
+
rb_global_variable(&cBigDecimal);
|
576
621
|
|
577
622
|
cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
|
623
|
+
rb_undef_alloc_func(cMysql2Statement);
|
624
|
+
rb_global_variable(&cMysql2Statement);
|
625
|
+
|
578
626
|
rb_define_method(cMysql2Statement, "param_count", rb_mysql_stmt_param_count, 0);
|
579
627
|
rb_define_method(cMysql2Statement, "field_count", rb_mysql_stmt_field_count, 0);
|
580
628
|
rb_define_method(cMysql2Statement, "_execute", rb_mysql_stmt_execute, -1);
|
@@ -599,4 +647,5 @@ void init_mysql2_statement() {
|
|
599
647
|
|
600
648
|
intern_to_s = rb_intern("to_s");
|
601
649
|
intern_merge_bang = rb_intern("merge!");
|
650
|
+
intern_query_options = rb_intern("@query_options");
|
602
651
|
}
|