mysql2 0.5.3 → 0.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +107 -22
- data/ext/mysql2/client.c +195 -53
- data/ext/mysql2/client.h +9 -2
- data/ext/mysql2/extconf.rb +58 -6
- data/ext/mysql2/mysql2_ext.c +6 -1
- data/ext/mysql2/mysql2_ext.h +13 -0
- data/ext/mysql2/result.c +270 -11
- data/ext/mysql2/result.h +1 -0
- data/ext/mysql2/statement.c +59 -12
- data/lib/mysql2/client.rb +23 -2
- data/lib/mysql2/error.rb +1 -0
- data/lib/mysql2/statement.rb +1 -3
- data/lib/mysql2/version.rb +1 -1
- data/lib/mysql2.rb +2 -0
- data/support/3A79BD29.asc +49 -0
- data/support/C74CD1D8.asc +104 -0
- data/support/mysql_enc_to_ruby.rb +1 -1
- metadata +10 -3
data/ext/mysql2/result.c
CHANGED
@@ -17,9 +17,27 @@ static rb_encoding *binaryEncoding;
|
|
17
17
|
*/
|
18
18
|
#define MYSQL2_MIN_TIME 2678400ULL
|
19
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
|
+
|
20
38
|
#define GET_RESULT(self) \
|
21
39
|
mysql2_result_wrapper *wrapper; \
|
22
|
-
|
40
|
+
TypedData_Get_Struct(self, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
|
23
41
|
|
24
42
|
typedef struct {
|
25
43
|
int symbolizeKeys;
|
@@ -47,11 +65,11 @@ static VALUE sym_symbolize_keys, sym_as, sym_array, sym_database_timezone,
|
|
47
65
|
static void rb_mysql_result_mark(void * wrapper) {
|
48
66
|
mysql2_result_wrapper * w = wrapper;
|
49
67
|
if (w) {
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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);
|
55
73
|
}
|
56
74
|
}
|
57
75
|
|
@@ -113,6 +131,48 @@ static void rb_mysql_result_free(void *ptr) {
|
|
113
131
|
xfree(wrapper);
|
114
132
|
}
|
115
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
|
+
|
116
176
|
static VALUE rb_mysql_result_free_(VALUE self) {
|
117
177
|
GET_RESULT(self);
|
118
178
|
rb_mysql_result_free_result(wrapper);
|
@@ -157,11 +217,18 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
|
|
157
217
|
rb_field = rb_intern3(field->name, field->name_length, rb_utf8_encoding());
|
158
218
|
rb_field = ID2SYM(rb_field);
|
159
219
|
} else {
|
160
|
-
|
161
|
-
|
162
|
-
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) {
|
163
228
|
rb_field = rb_str_export_to_enc(rb_field, default_internal_enc);
|
164
229
|
}
|
230
|
+
rb_obj_freeze(rb_field);
|
231
|
+
#endif
|
165
232
|
}
|
166
233
|
rb_ary_store(wrapper->fields, idx, rb_field);
|
167
234
|
}
|
@@ -169,9 +236,171 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, int symbo
|
|
169
236
|
return rb_field;
|
170
237
|
}
|
171
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
|
+
|
172
401
|
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
173
402
|
/* if binary flag is set, respect its wishes */
|
174
|
-
if (field.flags & BINARY_FLAG && field.charsetnr ==
|
403
|
+
if (field.flags & BINARY_FLAG && field.charsetnr == MYSQL2_BINARY_CHARSET) {
|
175
404
|
rb_enc_associate(val, binaryEncoding);
|
176
405
|
} else if (!field.charsetnr) {
|
177
406
|
/* MySQL 4.x may not provide an encoding, binary will get the bytes through */
|
@@ -182,7 +411,7 @@ static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_e
|
|
182
411
|
int enc_index;
|
183
412
|
|
184
413
|
enc_name = (field.charsetnr-1 < MYSQL2_CHARSETNR_SIZE) ? mysql2_mysql_enc_to_rb[field.charsetnr-1] : NULL;
|
185
|
-
|
414
|
+
|
186
415
|
if (enc_name != NULL) {
|
187
416
|
/* use the field encoding we were able to match */
|
188
417
|
enc_index = rb_enc_find_index(enc_name);
|
@@ -716,6 +945,25 @@ static VALUE rb_mysql_result_fetch_fields(VALUE self) {
|
|
716
945
|
return wrapper->fields;
|
717
946
|
}
|
718
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
|
+
|
719
967
|
static VALUE rb_mysql_result_each_(VALUE self,
|
720
968
|
VALUE(*fetch_row_func)(VALUE, MYSQL_FIELD *fields, const result_each_args *args),
|
721
969
|
const result_each_args *args)
|
@@ -927,13 +1175,18 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
927
1175
|
VALUE obj;
|
928
1176
|
mysql2_result_wrapper * wrapper;
|
929
1177
|
|
1178
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
1179
|
+
obj = TypedData_Make_Struct(cMysql2Result, mysql2_result_wrapper, &rb_mysql_result_type, wrapper);
|
1180
|
+
#else
|
930
1181
|
obj = Data_Make_Struct(cMysql2Result, mysql2_result_wrapper, rb_mysql_result_mark, rb_mysql_result_free, wrapper);
|
1182
|
+
#endif
|
931
1183
|
wrapper->numberOfFields = 0;
|
932
1184
|
wrapper->numberOfRows = 0;
|
933
1185
|
wrapper->lastRowProcessed = 0;
|
934
1186
|
wrapper->resultFreed = 0;
|
935
1187
|
wrapper->result = r;
|
936
1188
|
wrapper->fields = Qnil;
|
1189
|
+
wrapper->fieldTypes = Qnil;
|
937
1190
|
wrapper->rows = Qnil;
|
938
1191
|
wrapper->encoding = encoding;
|
939
1192
|
wrapper->streamingComplete = 0;
|
@@ -966,11 +1219,17 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
|
|
966
1219
|
|
967
1220
|
void init_mysql2_result() {
|
968
1221
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
1222
|
+
rb_global_variable(&cDate);
|
969
1223
|
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
1224
|
+
rb_global_variable(&cDateTime);
|
970
1225
|
|
971
1226
|
cMysql2Result = rb_define_class_under(mMysql2, "Result", rb_cObject);
|
1227
|
+
rb_undef_alloc_func(cMysql2Result);
|
1228
|
+
rb_global_variable(&cMysql2Result);
|
1229
|
+
|
972
1230
|
rb_define_method(cMysql2Result, "each", rb_mysql_result_each, -1);
|
973
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);
|
974
1233
|
rb_define_method(cMysql2Result, "free", rb_mysql_result_free_, 0);
|
975
1234
|
rb_define_method(cMysql2Result, "count", rb_mysql_result_count, 0);
|
976
1235
|
rb_define_alias(cMysql2Result, "size", "count");
|
data/ext/mysql2/result.h
CHANGED
data/ext/mysql2/statement.c
CHANGED
@@ -6,9 +6,13 @@ static VALUE sym_stream, intern_new_with_args, intern_each, intern_to_s, intern_
|
|
6
6
|
static VALUE intern_sec_fraction, intern_usec, intern_sec, intern_min, intern_hour, intern_day, intern_month, intern_year,
|
7
7
|
intern_query_options;
|
8
8
|
|
9
|
+
#ifndef NEW_TYPEDDATA_WRAPPER
|
10
|
+
#define TypedData_Get_Struct(obj, type, ignore, sval) Data_Get_Struct(obj, type, sval)
|
11
|
+
#endif
|
12
|
+
|
9
13
|
#define GET_STATEMENT(self) \
|
10
14
|
mysql_stmt_wrapper *stmt_wrapper; \
|
11
|
-
|
15
|
+
TypedData_Get_Struct(self, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper); \
|
12
16
|
if (!stmt_wrapper->stmt) { rb_raise(cMysql2Error, "Invalid statement handle"); } \
|
13
17
|
if (stmt_wrapper->closed) { rb_raise(cMysql2Error, "Statement handle already closed"); }
|
14
18
|
|
@@ -16,9 +20,45 @@ static void rb_mysql_stmt_mark(void * ptr) {
|
|
16
20
|
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
17
21
|
if (!stmt_wrapper) return;
|
18
22
|
|
19
|
-
|
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);
|
20
29
|
}
|
21
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
|
+
|
22
62
|
static void *nogvl_stmt_close(void *ptr) {
|
23
63
|
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
24
64
|
if (stmt_wrapper->stmt) {
|
@@ -28,11 +68,6 @@ static void *nogvl_stmt_close(void *ptr) {
|
|
28
68
|
return NULL;
|
29
69
|
}
|
30
70
|
|
31
|
-
static void rb_mysql_stmt_free(void *ptr) {
|
32
|
-
mysql_stmt_wrapper *stmt_wrapper = ptr;
|
33
|
-
decr_mysql2_stmt(stmt_wrapper);
|
34
|
-
}
|
35
|
-
|
36
71
|
void decr_mysql2_stmt(mysql_stmt_wrapper *stmt_wrapper) {
|
37
72
|
stmt_wrapper->refcount--;
|
38
73
|
|
@@ -46,7 +81,7 @@ void rb_raise_mysql2_stmt_error(mysql_stmt_wrapper *stmt_wrapper) {
|
|
46
81
|
VALUE e;
|
47
82
|
GET_CLIENT(stmt_wrapper->client);
|
48
83
|
VALUE rb_error_msg = rb_str_new2(mysql_stmt_error(stmt_wrapper->stmt));
|
49
|
-
VALUE rb_sql_state =
|
84
|
+
VALUE rb_sql_state = rb_str_new2(mysql_stmt_sqlstate(stmt_wrapper->stmt));
|
50
85
|
|
51
86
|
rb_encoding *conn_enc;
|
52
87
|
conn_enc = rb_to_encoding(wrapper->encoding);
|
@@ -96,7 +131,11 @@ VALUE rb_mysql_stmt_new(VALUE rb_client, VALUE sql) {
|
|
96
131
|
|
97
132
|
Check_Type(sql, T_STRING);
|
98
133
|
|
134
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
135
|
+
rb_stmt = TypedData_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, &rb_mysql_statement_type, stmt_wrapper);
|
136
|
+
#else
|
99
137
|
rb_stmt = Data_Make_Struct(cMysql2Statement, mysql_stmt_wrapper, rb_mysql_stmt_mark, rb_mysql_stmt_free, stmt_wrapper);
|
138
|
+
#endif
|
100
139
|
{
|
101
140
|
stmt_wrapper->client = rb_client;
|
102
141
|
stmt_wrapper->refcount = 1;
|
@@ -448,7 +487,7 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
|
|
448
487
|
if (metadata == NULL) {
|
449
488
|
if (mysql_stmt_errno(stmt) != 0) {
|
450
489
|
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
|
451
|
-
wrapper->
|
490
|
+
wrapper->active_fiber = Qnil;
|
452
491
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
453
492
|
}
|
454
493
|
// no data and no error, so query was not a SELECT
|
@@ -456,12 +495,12 @@ static VALUE rb_mysql_stmt_execute(int argc, VALUE *argv, VALUE self) {
|
|
456
495
|
}
|
457
496
|
|
458
497
|
if (!is_streaming) {
|
459
|
-
//
|
498
|
+
// receive the whole result set from the server
|
460
499
|
if (mysql_stmt_store_result(stmt)) {
|
461
500
|
mysql_free_result(metadata);
|
462
501
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
463
502
|
}
|
464
|
-
wrapper->
|
503
|
+
wrapper->active_fiber = Qnil;
|
465
504
|
}
|
466
505
|
|
467
506
|
resultObj = rb_mysql_result_to_obj(stmt_wrapper->client, wrapper->encoding, current, metadata, self);
|
@@ -502,7 +541,7 @@ static VALUE rb_mysql_stmt_fields(VALUE self) {
|
|
502
541
|
if (metadata == NULL) {
|
503
542
|
if (mysql_stmt_errno(stmt) != 0) {
|
504
543
|
// either CR_OUT_OF_MEMORY or CR_UNKNOWN_ERROR. both fatal.
|
505
|
-
wrapper->
|
544
|
+
wrapper->active_fiber = Qnil;
|
506
545
|
rb_raise_mysql2_stmt_error(stmt_wrapper);
|
507
546
|
}
|
508
547
|
// no data and no error, so query was not a SELECT
|
@@ -572,10 +611,18 @@ static VALUE rb_mysql_stmt_close(VALUE self) {
|
|
572
611
|
|
573
612
|
void init_mysql2_statement() {
|
574
613
|
cDate = rb_const_get(rb_cObject, rb_intern("Date"));
|
614
|
+
rb_global_variable(&cDate);
|
615
|
+
|
575
616
|
cDateTime = rb_const_get(rb_cObject, rb_intern("DateTime"));
|
617
|
+
rb_global_variable(&cDateTime);
|
618
|
+
|
576
619
|
cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
|
620
|
+
rb_global_variable(&cBigDecimal);
|
577
621
|
|
578
622
|
cMysql2Statement = rb_define_class_under(mMysql2, "Statement", rb_cObject);
|
623
|
+
rb_undef_alloc_func(cMysql2Statement);
|
624
|
+
rb_global_variable(&cMysql2Statement);
|
625
|
+
|
579
626
|
rb_define_method(cMysql2Statement, "param_count", rb_mysql_stmt_param_count, 0);
|
580
627
|
rb_define_method(cMysql2Statement, "field_count", rb_mysql_stmt_field_count, 0);
|
581
628
|
rb_define_method(cMysql2Statement, "_execute", rb_mysql_stmt_execute, -1);
|
data/lib/mysql2/client.rb
CHANGED
@@ -20,6 +20,7 @@ module Mysql2
|
|
20
20
|
|
21
21
|
def initialize(opts = {})
|
22
22
|
raise Mysql2::Error, "Options parameter must be a Hash" unless opts.is_a? Hash
|
23
|
+
|
23
24
|
opts = Mysql2::Util.key_hash_as_symbols(opts)
|
24
25
|
@read_timeout = nil
|
25
26
|
@query_options = self.class.default_query_options.dup
|
@@ -33,6 +34,7 @@ module Mysql2
|
|
33
34
|
# TODO: stricter validation rather than silent massaging
|
34
35
|
%i[reconnect connect_timeout local_infile read_timeout write_timeout default_file default_group secure_auth init_command automatic_close enable_cleartext_plugin default_auth].each do |key|
|
35
36
|
next unless opts.key?(key)
|
37
|
+
|
36
38
|
case key
|
37
39
|
when :reconnect, :local_infile, :secure_auth, :automatic_close, :enable_cleartext_plugin
|
38
40
|
send(:"#{key}=", !!opts[key]) # rubocop:disable Style/DoubleNegation
|
@@ -46,9 +48,14 @@ module Mysql2
|
|
46
48
|
# force the encoding to utf8
|
47
49
|
self.charset_name = opts[:encoding] || 'utf8'
|
48
50
|
|
51
|
+
mode = parse_ssl_mode(opts[:ssl_mode]) if opts[:ssl_mode]
|
52
|
+
if (mode == SSL_MODE_VERIFY_CA || mode == SSL_MODE_VERIFY_IDENTITY) && !opts[:sslca]
|
53
|
+
opts[:sslca] = find_default_ca_path
|
54
|
+
end
|
55
|
+
|
49
56
|
ssl_options = opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher)
|
50
57
|
ssl_set(*ssl_options) if ssl_options.any? || opts.key?(:sslverify)
|
51
|
-
self.ssl_mode =
|
58
|
+
self.ssl_mode = mode if mode
|
52
59
|
|
53
60
|
flags = case opts[:flags]
|
54
61
|
when Array
|
@@ -115,10 +122,23 @@ module Mysql2
|
|
115
122
|
end
|
116
123
|
end
|
117
124
|
|
125
|
+
# Find any default system CA paths to handle system roots
|
126
|
+
# by default if stricter validation is requested and no
|
127
|
+
# path is provide.
|
128
|
+
def find_default_ca_path
|
129
|
+
[
|
130
|
+
"/etc/ssl/certs/ca-certificates.crt",
|
131
|
+
"/etc/pki/tls/certs/ca-bundle.crt",
|
132
|
+
"/etc/ssl/ca-bundle.pem",
|
133
|
+
"/etc/ssl/cert.pem",
|
134
|
+
].find { |f| File.exist?(f) }
|
135
|
+
end
|
136
|
+
|
118
137
|
# Set default program_name in performance_schema.session_connect_attrs
|
119
138
|
# and performance_schema.session_account_connect_attrs
|
120
139
|
def parse_connect_attrs(conn_attrs)
|
121
140
|
return {} if Mysql2::Client::CONNECT_ATTRS.zero?
|
141
|
+
|
122
142
|
conn_attrs ||= {}
|
123
143
|
conn_attrs[:program_name] ||= $PROGRAM_NAME
|
124
144
|
conn_attrs.each_with_object({}) do |(key, value), hash|
|
@@ -127,7 +147,7 @@ module Mysql2
|
|
127
147
|
end
|
128
148
|
|
129
149
|
def query(sql, options = {})
|
130
|
-
Thread.handle_interrupt(::Mysql2::Util::
|
150
|
+
Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do
|
131
151
|
_query(sql, @query_options.merge(options))
|
132
152
|
end
|
133
153
|
end
|
@@ -135,6 +155,7 @@ module Mysql2
|
|
135
155
|
def query_info
|
136
156
|
info = query_info_string
|
137
157
|
return {} unless info
|
158
|
+
|
138
159
|
info_hash = {}
|
139
160
|
info.split.each_slice(2) { |s| info_hash[s[0].downcase.delete(':').to_sym] = s[1].to_i }
|
140
161
|
info_hash
|
data/lib/mysql2/error.rb
CHANGED
@@ -24,6 +24,7 @@ module Mysql2
|
|
24
24
|
1159 => ConnectionError, # ER_NET_READ_INTERRUPTED
|
25
25
|
1160 => ConnectionError, # ER_NET_ERROR_ON_WRITE
|
26
26
|
1161 => ConnectionError, # ER_NET_WRITE_INTERRUPTED
|
27
|
+
1927 => ConnectionError, # ER_CONNECTION_KILLED
|
27
28
|
|
28
29
|
2001 => ConnectionError, # CR_SOCKET_CREATE_ERROR
|
29
30
|
2002 => ConnectionError, # CR_CONNECTION_ERROR
|
data/lib/mysql2/statement.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
module Mysql2
|
2
2
|
class Statement
|
3
|
-
include Enumerable
|
4
|
-
|
5
3
|
def execute(*args, **kwargs)
|
6
|
-
Thread.handle_interrupt(::Mysql2::Util::
|
4
|
+
Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do
|
7
5
|
_execute(*args, **kwargs)
|
8
6
|
end
|
9
7
|
end
|
data/lib/mysql2/version.rb
CHANGED
data/lib/mysql2.rb
CHANGED
@@ -65,6 +65,7 @@ module Mysql2
|
|
65
65
|
#
|
66
66
|
def self.key_hash_as_symbols(hash)
|
67
67
|
return nil unless hash
|
68
|
+
|
68
69
|
Hash[hash.map { |k, v| [k.to_sym, v] }]
|
69
70
|
end
|
70
71
|
|
@@ -82,5 +83,6 @@ module Mysql2
|
|
82
83
|
else
|
83
84
|
::Timeout::Error
|
84
85
|
end
|
86
|
+
TIMEOUT_ERROR_NEVER = { TIMEOUT_ERROR_CLASS => :never }.freeze
|
85
87
|
end
|
86
88
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
2
|
+
Version: SKS 1.1.6
|
3
|
+
Comment: Hostname: pgp.mit.edu
|
4
|
+
|
5
|
+
mQINBGG4urcBEACrbsRa7tSSyxSfFkB+KXSbNM9rxYqoB78u107skReefq4/+Y72TpDvlDZL
|
6
|
+
mdv/lK0IpLa3bnvsM9IE1trNLrfi+JES62kaQ6hePPgn2RqxyIirt2seSi3Z3n3jlEg+mSdh
|
7
|
+
AvW+b+hFnqxo+TY0U+RBwDi4oO0YzHefkYPSmNPdlxRPQBMv4GPTNfxERx6XvVSPcL1+jQ4R
|
8
|
+
2cQFBryNhidBFIkoCOszjWhm+WnbURsLheBp757lqEyrpCufz77zlq2gEi+wtPHItfqsx3rz
|
9
|
+
xSRqatztMGYZpNUHNBJkr13npZtGW+kdN/xu980QLZxN+bZ88pNoOuzD6dKcpMJ0LkdUmTx5
|
10
|
+
z9ewiFiFbUDzZ7PECOm2g3veJrwr79CXDLE1+39Hr8rDM2kDhSr9tAlPTnHVDcaYIGgSNIBc
|
11
|
+
YfLmt91133klHQHBIdWCNVtWJjq5YcLQJ9TxG9GQzgABPrm6NDd1t9j7w1L7uwBvMB1wgpir
|
12
|
+
RTPVfnUSCd+025PEF+wTcBhfnzLtFj5xD7mNsmDmeHkF/sDfNOfAzTE1v2wq0ndYU60xbL6/
|
13
|
+
yl/Nipyr7WiQjCG0m3WfkjjVDTfs7/DXUqHFDOu4WMF9v+oqwpJXmAeGhQTWZC/QhWtrjrNJ
|
14
|
+
AgwKpp263gDSdW70ekhRzsok1HJwX1SfxHJYCMFs2aH6ppzNsQARAQABtDZNeVNRTCBSZWxl
|
15
|
+
YXNlIEVuZ2luZWVyaW5nIDxteXNxbC1idWlsZEBvc3Mub3JhY2xlLmNvbT6JAlQEEwEIAD4W
|
16
|
+
IQSFm+jXxYb1OEMLGcJGe5QtOnm9KQUCYbi6twIbAwUJA8JnAAULCQgHAgYVCgkICwIEFgID
|
17
|
+
AQIeAQIXgAAKCRBGe5QtOnm9KUewD/992sS31WLGoUQ6NoL7qOB4CErkqXtMzpJAKKg2jtBG
|
18
|
+
G3rKE1/0VAg1D8AwEK4LcCO407wohnH0hNiUbeDck5x20pgS5SplQpuXX1K9vPzHeL/WNTb9
|
19
|
+
8S3H2Mzj4o9obED6Ey52tTupttMF8pC9TJ93LxbJlCHIKKwCA1cXud3GycRN72eqSqZfJGds
|
20
|
+
aeWLmFmHf6oee27d8XLoNjbyAxna/4jdWoTqmp8oT3bgv/TBco23NzqUSVPi+7ljS1hHvcJu
|
21
|
+
oJYqaztGrAEf/lWIGdfl/kLEh8IYx8OBNUojh9mzCDlwbs83CBqoUdlzLNDdwmzu34Aw7xK1
|
22
|
+
4RAVinGFCpo/7EWoX6weyB/zqevUIIE89UABTeFoGih/hx2jdQV/NQNthWTW0jH0hmPnajBV
|
23
|
+
AJPYwAuO82rx2pnZCxDATMn0elOkTue3PCmzHBF/GT6c65aQC4aojj0+Veh787QllQ9FrWbw
|
24
|
+
nTz+4fNzU/MBZtyLZ4JnsiWUs9eJ2V1g/A+RiIKu357Qgy1ytLqlgYiWfzHFlYjdtbPYKjDa
|
25
|
+
ScnvtY8VO2Rktm7XiV4zKFKiaWp+vuVYpR0/7Adgnlj5Jt9lQQGOr+Z2VYx8SvBcC+by3XAt
|
26
|
+
YkRHtX5u4MLlVS3gcoWfDiWwCpvqdK21EsXjQJxRr3dbSn0HaVj4FJZX0QQ7WZm6WLkCDQRh
|
27
|
+
uLq3ARAA6RYjqfC0YcLGKvHhoBnsX29vy9Wn1y2JYpEnPUIB8X0VOyz5/ALv4Hqtl4THkH+m
|
28
|
+
mMuhtndoq2BkCCk508jWBvKS1S+Bd2esB45BDDmIhuX3ozu9Xza4i1FsPnLkQ0uMZJv30ls2
|
29
|
+
pXFmskhYyzmo6aOmH2536LdtPSlXtywfNV1HEr69V/AHbrEzfoQkJ/qvPzELBOjfjwtDPDeP
|
30
|
+
iVgW9LhktzVzn/BjO7XlJxw4PGcxJG6VApsXmM3t2fPN9eIHDUq8ocbHdJ4en8/bJDXZd9eb
|
31
|
+
QoILUuCg46hE3p6nTXfnPwSRnIRnsgCzeAz4rxDR4/Gv1Xpzv5wqpL21XQi3nvZKlcv7J1IR
|
32
|
+
VdphK66De9GpVQVTqC102gqJUErdjGmxmyCA1OOORqEPfKTrXz5YUGsWwpH+4xCuNQP0qmre
|
33
|
+
Rw3ghrH8potIr0iOVXFic5vJfBTgtcuEB6E6ulAN+3jqBGTaBML0jxgj3Z5VC5HKVbpg2DbB
|
34
|
+
/wMrLwFHNAbzV5hj2Os5Zmva0ySP1YHB26pAW8dwB38GBaQvfZq3ezM4cRAo/iJ/GsVE98dZ
|
35
|
+
EBO+Ml+0KYj+ZG+vyxzo20sweun7ZKT+9qZM90f6cQ3zqX6IfXZHHmQJBNv73mcZWNhDQOHs
|
36
|
+
4wBoq+FGQWNqLU9xaZxdXw80r1viDAwOy13EUtcVbTkAEQEAAYkCPAQYAQgAJhYhBIWb6NfF
|
37
|
+
hvU4QwsZwkZ7lC06eb0pBQJhuLq3AhsMBQkDwmcAAAoJEEZ7lC06eb0pSi8P/iy+dNnxrtiE
|
38
|
+
Nn9vkkA7AmZ8RsvPXYVeDCDSsL7UfhbS77r2L1qTa2aB3gAZUDIOXln51lSxMeeLtOequLME
|
39
|
+
V2Xi5km70rdtnja5SmWfc9fyExunXnsOhg6UG872At5CGEZU0c2Nt/hlGtOR3xbt3O/Uwl+d
|
40
|
+
ErQPA4BUbW5K1T7OC6oPvtlKfF4bGZFloHgt2yE9YSNWZsTPe6XJSapemHZLPOxJLnhs3VBi
|
41
|
+
rWE31QS0bRl5AzlO/fg7ia65vQGMOCOTLpgChTbcZHtozeFqva4IeEgE4xN+6r8WtgSYeGGD
|
42
|
+
RmeMEVjPM9dzQObf+SvGd58u2z9f2agPK1H32c69RLoA0mHRe7Wkv4izeJUc5tumUY0e8Ojd
|
43
|
+
enZZjT3hjLh6tM+mrp2oWnQIoed4LxUw1dhMOj0rYXv6laLGJ1FsW5eSke7ohBLcfBBTKnMC
|
44
|
+
BohROHy2E63Wggfsdn3UYzfqZ8cfbXetkXuLS/OM3MXbiNjg+ElYzjgWrkayu7yLakZx+mx6
|
45
|
+
sHPIJYm2hzkniMG29d5mGl7ZT9emP9b+CfqGUxoXJkjs0gnDl44bwGJ0dmIBu3ajVAaHODXy
|
46
|
+
Y/zdDMGjskfEYbNXCAY2FRZSE58tgTvPKD++Kd2KGplMU2EIFT7JYfKhHAB5DGMkx92HUMid
|
47
|
+
sTSKHe+QnnnoFmu4gnmDU31i
|
48
|
+
=Xqbo
|
49
|
+
-----END PGP PUBLIC KEY BLOCK-----
|