mysql2 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|
+
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
|
47
|
+
sTSKHe+QnnnoFmu4gnmDU31i
|
48
|
+
=Xqbo
|
49
|
+
-----END PGP PUBLIC KEY BLOCK-----
|