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.
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
- Data_Get_Struct(self, mysql2_result_wrapper, wrapper);
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
- rb_gc_mark(w->fields);
51
- rb_gc_mark(w->rows);
52
- rb_gc_mark(w->encoding);
53
- rb_gc_mark(w->client);
54
- rb_gc_mark(w->statement);
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
- rb_field = rb_str_new(field->name, field->name_length);
161
- rb_enc_associate(rb_field, conn_enc);
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 == 63) {
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
@@ -6,6 +6,7 @@ VALUE rb_mysql_result_to_obj(VALUE client, VALUE encoding, VALUE options, MYSQL_
6
6
 
7
7
  typedef struct {
8
8
  VALUE fields;
9
+ VALUE fieldTypes;
9
10
  VALUE rows;
10
11
  VALUE client;
11
12
  VALUE encoding;
@@ -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
- Data_Get_Struct(self, mysql_stmt_wrapper, stmt_wrapper); \
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
- rb_gc_mark(stmt_wrapper->client);
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 = rb_tainted_str_new2(mysql_stmt_sqlstate(stmt_wrapper->stmt));
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->active_thread = Qnil;
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
- // recieve the whole result set from the server
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->active_thread = Qnil;
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->active_thread = Qnil;
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 = parse_ssl_mode(opts[:ssl_mode]) if opts[: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::TIMEOUT_ERROR_CLASS => :never) do
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
@@ -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::TIMEOUT_ERROR_CLASS => :never) do
4
+ Thread.handle_interrupt(::Mysql2::Util::TIMEOUT_ERROR_NEVER) do
7
5
  _execute(*args, **kwargs)
8
6
  end
9
7
  end
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.5.3".freeze
2
+ VERSION = "0.5.5".freeze
3
3
  end
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-----