mysql2-replication 1.0.4 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dae33ecb6c6b2ecfade5316344529e995ef41efefbf22791cef85b07c14253f6
4
- data.tar.gz: 9407c34a9d180cb06ee7e22072db0f4727213ef96e5134f6c47c7e2c7aef48d2
3
+ metadata.gz: 86bbdf34e4db1d1d3379cdb75056fb9df7c4ef011362ac9356ff7bc3ff0113cd
4
+ data.tar.gz: c7b5dc5ad8fa263375deba6613466a1576fca8bfad288b967e6cbc1101e459c2
5
5
  SHA512:
6
- metadata.gz: c991529269be9df8fb90d312ff644eb069103dc80538c5c5f0484a04d9bfd12b8218e164e48aff82011646a2bd3a9a1f827050211277d676ff3cb0c8095775c1
7
- data.tar.gz: 6c56fc58282cff73dc930f791945bdf23d872df53e70b3b655c0e7dbb78a0c89823d8105438856aee8d642f10b793599932a26b60100fdf19824fffd60d65cf2
6
+ metadata.gz: 74a50bc506b77572906cb977c9523bd3bcf00fcf038e12b53bb33cd6e409a1e85d680ca66ca3ce7c8d546102a3c4bbce704bce33fbea19aa3a9cb6c8cf4a08c2
7
+ data.tar.gz: 0a102c99217563a81df6d419ff11e94008bb59ad9bebd1e32bb05187d07033aecb65958ac238d8e6d3574346041523c93a64177d6d30109ab8a1805a757a185a
@@ -22,7 +22,9 @@ void Init_mysql2_replication(void);
22
22
 
23
23
  static VALUE rb_cDate;
24
24
 
25
- static VALUE rb_cMysql2Error;
25
+ static VALUE rb_eMysql2Error;
26
+
27
+ static VALUE rb_eMysql2ReplicationError;
26
28
 
27
29
  static VALUE rb_cMysql2ReplicationEvent;
28
30
  static VALUE rb_cMysql2ReplicationRotateEvent;
@@ -336,6 +338,37 @@ rbm2_metadata_parse(enum enum_field_types *column_type,
336
338
  }
337
339
  }
338
340
 
341
+ static inline VALUE
342
+ rbm2_column_parse_variable_size_uint(VALUE rb_column,
343
+ const uint8_t **row_data)
344
+ {
345
+ VALUE rb_size = rb_hash_aref(rb_column, rb_id2sym(rb_intern("size")));
346
+ uint32_t size = NUM2UINT(rb_size);
347
+ VALUE rb_value = RUBY_Qnil;
348
+ switch (size) {
349
+ case 1:
350
+ rb_value = USHORT2NUM(rbm2_read_uint8(*row_data));
351
+ break;
352
+ case 2:
353
+ rb_value = USHORT2NUM(rbm2_read_uint16(*row_data));
354
+ break;
355
+ case 3:
356
+ rb_value = UINT2NUM(rbm2_read_uint24(*row_data));
357
+ break;
358
+ case 4:
359
+ rb_value = UINT2NUM(rbm2_read_uint32(*row_data));
360
+ break;
361
+ default:
362
+ rb_raise(rb_eNotImpError,
363
+ "unsupported size for variable size uint: %u: %+" PRIsVALUE,
364
+ size,
365
+ rb_column);
366
+ break;
367
+ }
368
+ (*row_data) += size;
369
+ return rb_value;
370
+ }
371
+
339
372
  static inline VALUE
340
373
  rbm2_column_parse_variable_length_string(VALUE rb_column,
341
374
  const uint8_t **row_data)
@@ -409,8 +442,9 @@ rbm2_column_parse_blob(VALUE rb_column,
409
442
  break;
410
443
  default:
411
444
  rb_raise(rb_eNotImpError,
412
- "unsupported length size for blob: %u",
413
- length_size);
445
+ "unsupported length size for blob: %u: %+" PRIsVALUE,
446
+ length_size,
447
+ rb_column);
414
448
  break;
415
449
  }
416
450
  return rb_value;
@@ -426,8 +460,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
426
460
  switch (type) {
427
461
  case MYSQL_TYPE_DECIMAL:
428
462
  rb_raise(rb_eNotImpError,
429
- "decimal type isn't implemented yet: %+" PRIsVALUE,
430
- rb_type);
463
+ "decimal type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
464
+ rb_type,
465
+ rb_column);
431
466
  break;
432
467
  case MYSQL_TYPE_TINY:
433
468
  rb_value = RB_CHR2FIX(*(*row_data));
@@ -476,12 +511,21 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
476
511
  M: 4bit
477
512
  D: 5bit
478
513
  */
479
- rb_value = rb_funcall(rb_cDate,
480
- rb_intern("new"),
481
- 3,
482
- RB_UINT2NUM((raw_date >> 9)),
483
- RB_UINT2NUM((raw_date >> 5) & ((1 << 4) - 1)),
484
- RB_UINT2NUM((raw_date & ((1 << 5) - 1))));
514
+ if (raw_date == 0) {
515
+ rb_value = rb_funcall(rb_cDate,
516
+ rb_intern("new"),
517
+ 3,
518
+ RB_UINT2NUM(0),
519
+ RB_UINT2NUM(1),
520
+ RB_UINT2NUM(1));
521
+ } else {
522
+ rb_value = rb_funcall(rb_cDate,
523
+ rb_intern("new"),
524
+ 3,
525
+ RB_UINT2NUM((raw_date >> 9)),
526
+ RB_UINT2NUM((raw_date >> 5) & ((1 << 4) - 1)),
527
+ RB_UINT2NUM((raw_date & ((1 << 5) - 1))));
528
+ }
485
529
  (*row_data) += 3;
486
530
  }
487
531
  break;
@@ -502,15 +546,22 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
502
546
  /* https://mariadb.com/kb/en/rows_event_v1/#mysql_type_datetime */
503
547
  uint64_t raw_time = rbm2_read_uint64(*row_data);
504
548
  /* YYYYMMDDHHMMSS */
505
- rb_value = rb_funcall(rb_cTime,
506
- rb_intern("utc"),
507
- 6,
508
- RB_UINT2NUM((raw_time / 10000000000)),
509
- RB_UINT2NUM((raw_time % 10000000000) / 100000000),
510
- RB_UINT2NUM((raw_time % 100000000) / 1000000),
511
- RB_UINT2NUM((raw_time % 1000000) / 10000),
512
- RB_UINT2NUM((raw_time % 10000) / 100),
513
- RB_UINT2NUM((raw_time % 100)));
549
+ if (raw_time == 0) {
550
+ rb_value = rb_funcall(rb_cTime,
551
+ rb_intern("utc"),
552
+ 1,
553
+ RB_UINT2NUM(0));
554
+ } else {
555
+ rb_value = rb_funcall(rb_cTime,
556
+ rb_intern("utc"),
557
+ 6,
558
+ RB_UINT2NUM((raw_time / 10000000000)),
559
+ RB_UINT2NUM((raw_time % 10000000000) / 100000000),
560
+ RB_UINT2NUM((raw_time % 100000000) / 1000000),
561
+ RB_UINT2NUM((raw_time % 1000000) / 10000),
562
+ RB_UINT2NUM((raw_time % 10000) / 100),
563
+ RB_UINT2NUM((raw_time % 100)));
564
+ }
514
565
  (*row_data) += 8;
515
566
  }
516
567
  break;
@@ -520,8 +571,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
520
571
  break;
521
572
  case MYSQL_TYPE_NEWDATE:
522
573
  rb_raise(rb_eNotImpError,
523
- "newdate type isn't implemented yet: %+" PRIsVALUE,
524
- rb_type);
574
+ "newdate type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
575
+ rb_type,
576
+ rb_column);
525
577
  break;
526
578
  case MYSQL_TYPE_VARCHAR:
527
579
  rb_value = rbm2_column_parse_variable_length_string(rb_column, row_data);
@@ -550,9 +602,11 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
550
602
  break;
551
603
  default :
552
604
  rb_raise(rb_eNotImpError,
553
- "%d bit type isn't implemented yet: %+" PRIsVALUE,
605
+ "%d bit type isn't implemented yet: %+" PRIsVALUE
606
+ ": %+" PRIsVALUE,
554
607
  bits,
555
- rb_type);
608
+ rb_type,
609
+ rb_column);
556
610
  break;
557
611
  }
558
612
  }
@@ -646,8 +700,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
646
700
  break;
647
701
  case MYSQL_TYPE_TIME2:
648
702
  rb_raise(rb_eNotImpError,
649
- "time2 type isn't implemented yet: %+" PRIsVALUE,
650
- rb_type);
703
+ "time2 type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
704
+ rb_type,
705
+ rb_column);
651
706
  break;
652
707
  case MYSQL_TYPE_JSON:
653
708
  rb_value = rbm2_column_parse_blob(rb_column, row_data);
@@ -683,16 +738,15 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
683
738
  break;
684
739
  case MYSQL_TYPE_ENUM:
685
740
  case MYSQL_TYPE_SET:
686
- rb_raise(rb_eNotImpError,
687
- "enum/set types aren't implemented yet: %+" PRIsVALUE,
688
- rb_type);
741
+ rb_value = rbm2_column_parse_variable_size_uint(rb_column, row_data);
689
742
  break;
690
743
  case MYSQL_TYPE_TINY_BLOB:
691
744
  case MYSQL_TYPE_MEDIUM_BLOB:
692
745
  case MYSQL_TYPE_LONG_BLOB:
693
746
  rb_raise(rb_eNotImpError,
694
- "blob types aren't implemented yet: %+" PRIsVALUE,
695
- rb_type);
747
+ "blob types aren't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
748
+ rb_type,
749
+ rb_column);
696
750
  break;
697
751
  case MYSQL_TYPE_BLOB:
698
752
  rb_value = rbm2_column_parse_blob(rb_column, row_data);
@@ -705,13 +759,17 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
705
759
  break;
706
760
  case MYSQL_TYPE_GEOMETRY:
707
761
  rb_raise(rb_eNotImpError,
708
- "geometry type isn't implemented yet: %+" PRIsVALUE,
709
- rb_type);
762
+ "geometry type isn't implemented yet: %+" PRIsVALUE
763
+ ": %+" PRIsVALUE,
764
+ rb_type,
765
+ rb_column);
710
766
  break;
711
767
  default:
712
768
  rb_raise(rb_eNotImpError,
713
- "unknown type isn't implemented yet: %+" PRIsVALUE,
714
- rb_type);
769
+ "unknown type isn't implemented yet: %+" PRIsVALUE
770
+ ": %+" PRIsVALUE,
771
+ rb_type,
772
+ rb_column);
715
773
  break;
716
774
  }
717
775
  return rb_value;
@@ -730,6 +788,7 @@ typedef struct
730
788
  VALUE rb_client;
731
789
  VALUE rb_table_maps;
732
790
  bool force_disable_use_checksum;
791
+ bool format_description_processed;
733
792
  } rbm2_replication_client_wrapper;
734
793
 
735
794
  static void
@@ -820,7 +879,7 @@ rbm2_replication_client_raise(VALUE self)
820
879
  rb_usascii_encoding());
821
880
  ID new_with_args;
822
881
  CONST_ID(new_with_args, "new_with_args");
823
- VALUE rb_error = rb_funcall(rb_cMysql2Error,
882
+ VALUE rb_error = rb_funcall(rb_eMysql2Error,
824
883
  new_with_args,
825
884
  4,
826
885
  rb_error_message,
@@ -877,6 +936,7 @@ rbm2_replication_client_initialize(int argc, VALUE *argv, VALUE self)
877
936
  } else {
878
937
  wrapper->force_disable_use_checksum = false;
879
938
  }
939
+ wrapper->format_description_processed = false;
880
940
 
881
941
  return RUBY_Qnil;
882
942
  }
@@ -1098,6 +1158,57 @@ rbm2_row_parse(const uint8_t **row_data,
1098
1158
  return rb_row;
1099
1159
  }
1100
1160
 
1161
+ typedef struct
1162
+ {
1163
+ struct st_mariadb_rpl_rows_event *rows_event;
1164
+ VALUE rb_klass;
1165
+ VALUE rb_rows;
1166
+ VALUE rb_updated_rows;
1167
+ VALUE rb_table_map;
1168
+ } rbm2_replication_rows_event_parse_rows_data;
1169
+
1170
+ static VALUE
1171
+ rbm2_replication_rows_event_parse_rows_body(VALUE user_data)
1172
+ {
1173
+ rbm2_replication_rows_event_parse_rows_data *data =
1174
+ (rbm2_replication_rows_event_parse_rows_data *)user_data;
1175
+
1176
+ const uint8_t *column_bitmap =
1177
+ (const uint8_t *)(data->rows_event->column_bitmap);
1178
+ const uint8_t *column_update_bitmap =
1179
+ (const uint8_t *)(data->rows_event->column_update_bitmap);
1180
+ const uint8_t *row_data = data->rows_event->row_data;
1181
+ const uint8_t *row_data_end = row_data + data->rows_event->row_data_size;
1182
+ VALUE rb_columns = rb_iv_get(data->rb_table_map, "@columns");
1183
+ while (row_data < row_data_end) {
1184
+ VALUE rb_row = rbm2_row_parse(&row_data,
1185
+ data->rows_event->column_count,
1186
+ column_bitmap,
1187
+ rb_columns);
1188
+ rb_ary_push(data->rb_rows, rb_row);
1189
+ if (data->rb_klass == rb_cMysql2ReplicationUpdateRowsEvent) {
1190
+ VALUE rb_updated_row = rbm2_row_parse(&row_data,
1191
+ data->rows_event->column_count,
1192
+ column_update_bitmap,
1193
+ rb_columns);
1194
+ rb_ary_push(data->rb_updated_rows, rb_updated_row);
1195
+ }
1196
+ }
1197
+ return RUBY_Qnil;
1198
+ }
1199
+
1200
+ static VALUE
1201
+ rbm2_replication_rows_event_parse_rows_rescue(VALUE user_data, VALUE error)
1202
+ {
1203
+ rbm2_replication_rows_event_parse_rows_data *data =
1204
+ (rbm2_replication_rows_event_parse_rows_data *)user_data;
1205
+ rb_raise(rb_eMysql2ReplicationError,
1206
+ "failed to parse rows: %+" PRIsVALUE ": %+" PRIsVALUE,
1207
+ data->rb_table_map,
1208
+ rb_funcall(error, rb_intern("message"), 0));
1209
+ return RUBY_Qnil;
1210
+ }
1211
+
1101
1212
  static VALUE
1102
1213
  rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1103
1214
  MARIADB_RPL_EVENT *event)
@@ -1111,15 +1222,17 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1111
1222
  {
1112
1223
  struct st_mariadb_rpl_rotate_event *e = &(event->event.rotate);
1113
1224
  rb_iv_set(rb_event, "@position", ULL2NUM(e->position));
1114
- size_t filename_size;
1225
+ size_t filename_size = e->filename.length;
1115
1226
  if (event->timestamp == 0) {
1116
1227
  /* Fake ROTATE_EVENT: https://mariadb.com/kb/en/fake-rotate_event/ */
1117
- filename_size = wrapper->rpl->buffer_size -
1118
- EVENT_HEADER_OFS -
1119
- sizeof(uint64_t) - /* position */
1120
- sizeof(uint32_t); /* checksum */
1121
- } else {
1122
- filename_size = e->filename.length;
1228
+ if (!wrapper->format_description_processed) {
1229
+ filename_size = wrapper->rpl->buffer_size -
1230
+ EVENT_HEADER_OFS -
1231
+ sizeof(uint64_t); /* position */
1232
+ if (!wrapper->force_disable_use_checksum) {
1233
+ filename_size -= sizeof(uint32_t); /* checksum */
1234
+ }
1235
+ }
1123
1236
  }
1124
1237
  rb_iv_set(rb_event,
1125
1238
  "@file_name",
@@ -1140,6 +1253,7 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1140
1253
  if (wrapper->force_disable_use_checksum) {
1141
1254
  wrapper->rpl->use_checksum = false;
1142
1255
  }
1256
+ wrapper->format_description_processed = true;
1143
1257
  break;
1144
1258
  case TABLE_MAP_EVENT:
1145
1259
  klass = rb_cMysql2ReplicationTableMapEvent;
@@ -1201,10 +1315,6 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1201
1315
  struct st_mariadb_rpl_rows_event *e = &(event->event.rows);
1202
1316
  VALUE rb_table_id = ULONG2NUM(e->table_id);
1203
1317
  VALUE rb_table_map = rb_hash_aref(wrapper->rb_table_maps, rb_table_id);
1204
- const uint8_t *column_bitmap =
1205
- (const uint8_t *)(e->column_bitmap);
1206
- const uint8_t *column_update_bitmap =
1207
- (const uint8_t *)(e->column_update_bitmap);
1208
1318
  rb_iv_set(rb_event, "@table_id", rb_table_id);
1209
1319
  rb_iv_set(rb_event, "@table_map", rb_table_map);
1210
1320
  rb_iv_set(rb_event, "@rows_flags", USHORT2NUM(e->flags));
@@ -1213,24 +1323,15 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1213
1323
  if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
1214
1324
  rb_updated_rows = rb_ary_new();
1215
1325
  }
1216
- const uint8_t *row_data = e->row_data;
1217
- const uint8_t *row_data_end = row_data + e->row_data_size;
1218
1326
  if (!RB_NIL_P(rb_table_map)) {
1219
- VALUE rb_columns = rb_iv_get(rb_table_map, "@columns");
1220
- while (row_data < row_data_end) {
1221
- VALUE rb_row = rbm2_row_parse(&row_data,
1222
- e->column_count,
1223
- column_bitmap,
1224
- rb_columns);
1225
- rb_ary_push(rb_rows, rb_row);
1226
- if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
1227
- VALUE rb_updated_row = rbm2_row_parse(&row_data,
1228
- e->column_count,
1229
- column_update_bitmap,
1230
- rb_columns);
1231
- rb_ary_push(rb_updated_rows, rb_updated_row);
1232
- }
1233
- }
1327
+ rbm2_replication_rows_event_parse_rows_data data;
1328
+ data.rows_event = e;
1329
+ data.rb_klass = klass;
1330
+ data.rb_rows = rb_rows;
1331
+ data.rb_updated_rows = rb_updated_rows;
1332
+ data.rb_table_map = rb_table_map;
1333
+ rb_rescue(rbm2_replication_rows_event_parse_rows_body, (VALUE)&data,
1334
+ rbm2_replication_rows_event_parse_rows_rescue, (VALUE)&data);
1234
1335
  }
1235
1336
  rb_iv_set(rb_event, "@rows", rb_rows);
1236
1337
  if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
@@ -1312,9 +1413,13 @@ Init_mysql2_replication(void)
1312
1413
  rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
1313
1414
 
1314
1415
  VALUE rb_mMysql2 = rb_const_get(rb_cObject, rb_intern("Mysql2"));
1315
- rb_cMysql2Error = rb_const_get(rb_mMysql2, rb_intern("Error"));
1416
+ rb_eMysql2Error = rb_const_get(rb_mMysql2, rb_intern("Error"));
1316
1417
 
1317
1418
  VALUE rb_mMysql2Replication = rb_define_module("Mysql2Replication");
1419
+ rb_eMysql2ReplicationError =
1420
+ rb_define_class_under(rb_mMysql2Replication,
1421
+ "Error",
1422
+ rb_eStandardError);
1318
1423
 
1319
1424
  rb_cMysql2ReplicationEvent =
1320
1425
  rb_define_class_under(rb_mMysql2Replication, "Event", rb_cObject);
@@ -1,3 +1,3 @@
1
1
  module Mysql2Replication
2
- VERSION = "1.0.4"
2
+ VERSION = "1.0.5"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql2-replication
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sutou Kouhei
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-07 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2