mysql2-replication 1.0.1 → 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: e4e53fa99301ddf9de5e0152b67093098271e727d7dbf21f4228bb0f1d1857cc
4
- data.tar.gz: 7345a93462c78c4d0fa7ff94f7c14e09005b4119366a58130855de1d3c94a7b6
3
+ metadata.gz: 86bbdf34e4db1d1d3379cdb75056fb9df7c4ef011362ac9356ff7bc3ff0113cd
4
+ data.tar.gz: c7b5dc5ad8fa263375deba6613466a1576fca8bfad288b967e6cbc1101e459c2
5
5
  SHA512:
6
- metadata.gz: 3d3cac78675064583fc9f02a6f362a1dc5d5ed75bc7ae61873e734697f72f14ab5c5fe87335370dbb4be3231d604140b0a1e258bc615c730582c9db441ce2823
7
- data.tar.gz: fb7bddd05753618b6fcef07c4e8ddea0ac611d9b94df1c80dd51671432799974b84667bb11d72475c405c73c80c56d90363a793fa5b036e29cb11dca3c83c1c8
6
+ metadata.gz: 74a50bc506b77572906cb977c9523bd3bcf00fcf038e12b53bb33cd6e409a1e85d680ca66ca3ce7c8d546102a3c4bbce704bce33fbea19aa3a9cb6c8cf4a08c2
7
+ data.tar.gz: 0a102c99217563a81df6d419ff11e94008bb59ad9bebd1e32bb05187d07033aecb65958ac238d8e6d3574346041523c93a64177d6d30109ab8a1805a757a185a
@@ -1,3 +1,5 @@
1
+ #include <stdbool.h>
2
+
1
3
  #include <ruby.h>
2
4
  #include <ruby/encoding.h>
3
5
  #include <ruby/thread.h>
@@ -10,11 +12,19 @@
10
12
  /* mysql2 */
11
13
  #include <client.h>
12
14
 
15
+
16
+ #ifndef RUBY_LL2NUM
17
+ # define RUBY_LL2NUM LL2NUM
18
+ #endif
19
+
20
+
13
21
  void Init_mysql2_replication(void);
14
22
 
15
23
  static VALUE rb_cDate;
16
24
 
17
- static VALUE rb_cMysql2Error;
25
+ static VALUE rb_eMysql2Error;
26
+
27
+ static VALUE rb_eMysql2ReplicationError;
18
28
 
19
29
  static VALUE rb_cMysql2ReplicationEvent;
20
30
  static VALUE rb_cMysql2ReplicationRotateEvent;
@@ -328,6 +338,37 @@ rbm2_metadata_parse(enum enum_field_types *column_type,
328
338
  }
329
339
  }
330
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
+
331
372
  static inline VALUE
332
373
  rbm2_column_parse_variable_length_string(VALUE rb_column,
333
374
  const uint8_t **row_data)
@@ -401,8 +442,9 @@ rbm2_column_parse_blob(VALUE rb_column,
401
442
  break;
402
443
  default:
403
444
  rb_raise(rb_eNotImpError,
404
- "unsupported length size for blob: %u",
405
- length_size);
445
+ "unsupported length size for blob: %u: %+" PRIsVALUE,
446
+ length_size,
447
+ rb_column);
406
448
  break;
407
449
  }
408
450
  return rb_value;
@@ -418,8 +460,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
418
460
  switch (type) {
419
461
  case MYSQL_TYPE_DECIMAL:
420
462
  rb_raise(rb_eNotImpError,
421
- "decimal type isn't implemented yet: %+" PRIsVALUE,
422
- rb_type);
463
+ "decimal type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
464
+ rb_type,
465
+ rb_column);
423
466
  break;
424
467
  case MYSQL_TYPE_TINY:
425
468
  rb_value = RB_CHR2FIX(*(*row_data));
@@ -468,12 +511,21 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
468
511
  M: 4bit
469
512
  D: 5bit
470
513
  */
471
- rb_value = rb_funcall(rb_cDate,
472
- rb_intern("new"),
473
- 3,
474
- RB_UINT2NUM((raw_date >> 9)),
475
- RB_UINT2NUM((raw_date >> 5) & ((1 << 4) - 1)),
476
- 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
+ }
477
529
  (*row_data) += 3;
478
530
  }
479
531
  break;
@@ -494,15 +546,22 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
494
546
  /* https://mariadb.com/kb/en/rows_event_v1/#mysql_type_datetime */
495
547
  uint64_t raw_time = rbm2_read_uint64(*row_data);
496
548
  /* YYYYMMDDHHMMSS */
497
- rb_value = rb_funcall(rb_cTime,
498
- rb_intern("utc"),
499
- 6,
500
- RB_UINT2NUM((raw_time / (10 * 10))),
501
- RB_UINT2NUM((raw_time % (10 * 10)) / (10 * 8)),
502
- RB_UINT2NUM((raw_time % (10 * 8)) / (10 * 6)),
503
- RB_UINT2NUM((raw_time % (10 * 6)) / (10 * 4)),
504
- RB_UINT2NUM((raw_time % (10 * 4)) / (10 * 2)),
505
- RB_UINT2NUM((raw_time % (10 * 2))));
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
+ }
506
565
  (*row_data) += 8;
507
566
  }
508
567
  break;
@@ -512,8 +571,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
512
571
  break;
513
572
  case MYSQL_TYPE_NEWDATE:
514
573
  rb_raise(rb_eNotImpError,
515
- "newdate type isn't implemented yet: %+" PRIsVALUE,
516
- rb_type);
574
+ "newdate type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
575
+ rb_type,
576
+ rb_column);
517
577
  break;
518
578
  case MYSQL_TYPE_VARCHAR:
519
579
  rb_value = rbm2_column_parse_variable_length_string(rb_column, row_data);
@@ -542,9 +602,11 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
542
602
  break;
543
603
  default :
544
604
  rb_raise(rb_eNotImpError,
545
- "%d bit type isn't implemented yet: %+" PRIsVALUE,
605
+ "%d bit type isn't implemented yet: %+" PRIsVALUE
606
+ ": %+" PRIsVALUE,
546
607
  bits,
547
- rb_type);
608
+ rb_type,
609
+ rb_column);
548
610
  break;
549
611
  }
550
612
  }
@@ -638,8 +700,9 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
638
700
  break;
639
701
  case MYSQL_TYPE_TIME2:
640
702
  rb_raise(rb_eNotImpError,
641
- "time2 type isn't implemented yet: %+" PRIsVALUE,
642
- rb_type);
703
+ "time2 type isn't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
704
+ rb_type,
705
+ rb_column);
643
706
  break;
644
707
  case MYSQL_TYPE_JSON:
645
708
  rb_value = rbm2_column_parse_blob(rb_column, row_data);
@@ -675,16 +738,15 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
675
738
  break;
676
739
  case MYSQL_TYPE_ENUM:
677
740
  case MYSQL_TYPE_SET:
678
- rb_raise(rb_eNotImpError,
679
- "enum/set types aren't implemented yet: %+" PRIsVALUE,
680
- rb_type);
741
+ rb_value = rbm2_column_parse_variable_size_uint(rb_column, row_data);
681
742
  break;
682
743
  case MYSQL_TYPE_TINY_BLOB:
683
744
  case MYSQL_TYPE_MEDIUM_BLOB:
684
745
  case MYSQL_TYPE_LONG_BLOB:
685
746
  rb_raise(rb_eNotImpError,
686
- "blob types aren't implemented yet: %+" PRIsVALUE,
687
- rb_type);
747
+ "blob types aren't implemented yet: %+" PRIsVALUE ": %+" PRIsVALUE,
748
+ rb_type,
749
+ rb_column);
688
750
  break;
689
751
  case MYSQL_TYPE_BLOB:
690
752
  rb_value = rbm2_column_parse_blob(rb_column, row_data);
@@ -697,13 +759,17 @@ rbm2_column_parse(VALUE rb_column, const uint8_t **row_data)
697
759
  break;
698
760
  case MYSQL_TYPE_GEOMETRY:
699
761
  rb_raise(rb_eNotImpError,
700
- "geometry type isn't implemented yet: %+" PRIsVALUE,
701
- rb_type);
762
+ "geometry type isn't implemented yet: %+" PRIsVALUE
763
+ ": %+" PRIsVALUE,
764
+ rb_type,
765
+ rb_column);
702
766
  break;
703
767
  default:
704
768
  rb_raise(rb_eNotImpError,
705
- "unknown type isn't implemented yet: %+" PRIsVALUE,
706
- rb_type);
769
+ "unknown type isn't implemented yet: %+" PRIsVALUE
770
+ ": %+" PRIsVALUE,
771
+ rb_type,
772
+ rb_column);
707
773
  break;
708
774
  }
709
775
  return rb_value;
@@ -722,6 +788,7 @@ typedef struct
722
788
  VALUE rb_client;
723
789
  VALUE rb_table_maps;
724
790
  bool force_disable_use_checksum;
791
+ bool format_description_processed;
725
792
  } rbm2_replication_client_wrapper;
726
793
 
727
794
  static void
@@ -812,7 +879,7 @@ rbm2_replication_client_raise(VALUE self)
812
879
  rb_usascii_encoding());
813
880
  ID new_with_args;
814
881
  CONST_ID(new_with_args, "new_with_args");
815
- VALUE rb_error = rb_funcall(rb_cMysql2Error,
882
+ VALUE rb_error = rb_funcall(rb_eMysql2Error,
816
883
  new_with_args,
817
884
  4,
818
885
  rb_error_message,
@@ -869,6 +936,7 @@ rbm2_replication_client_initialize(int argc, VALUE *argv, VALUE self)
869
936
  } else {
870
937
  wrapper->force_disable_use_checksum = false;
871
938
  }
939
+ wrapper->format_description_processed = false;
872
940
 
873
941
  return RUBY_Qnil;
874
942
  }
@@ -1090,6 +1158,57 @@ rbm2_row_parse(const uint8_t **row_data,
1090
1158
  return rb_row;
1091
1159
  }
1092
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
+
1093
1212
  static VALUE
1094
1213
  rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1095
1214
  MARIADB_RPL_EVENT *event)
@@ -1103,15 +1222,17 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1103
1222
  {
1104
1223
  struct st_mariadb_rpl_rotate_event *e = &(event->event.rotate);
1105
1224
  rb_iv_set(rb_event, "@position", ULL2NUM(e->position));
1106
- size_t filename_size;
1225
+ size_t filename_size = e->filename.length;
1107
1226
  if (event->timestamp == 0) {
1108
1227
  /* Fake ROTATE_EVENT: https://mariadb.com/kb/en/fake-rotate_event/ */
1109
- filename_size = wrapper->rpl->buffer_size -
1110
- EVENT_HEADER_OFS -
1111
- sizeof(uint64_t) - /* position */
1112
- sizeof(uint32_t); /* checksum */
1113
- } else {
1114
- 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
+ }
1115
1236
  }
1116
1237
  rb_iv_set(rb_event,
1117
1238
  "@file_name",
@@ -1132,6 +1253,7 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1132
1253
  if (wrapper->force_disable_use_checksum) {
1133
1254
  wrapper->rpl->use_checksum = false;
1134
1255
  }
1256
+ wrapper->format_description_processed = true;
1135
1257
  break;
1136
1258
  case TABLE_MAP_EVENT:
1137
1259
  klass = rb_cMysql2ReplicationTableMapEvent;
@@ -1193,10 +1315,6 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1193
1315
  struct st_mariadb_rpl_rows_event *e = &(event->event.rows);
1194
1316
  VALUE rb_table_id = ULONG2NUM(e->table_id);
1195
1317
  VALUE rb_table_map = rb_hash_aref(wrapper->rb_table_maps, rb_table_id);
1196
- const uint8_t *column_bitmap =
1197
- (const uint8_t *)(e->column_bitmap);
1198
- const uint8_t *column_update_bitmap =
1199
- (const uint8_t *)(e->column_update_bitmap);
1200
1318
  rb_iv_set(rb_event, "@table_id", rb_table_id);
1201
1319
  rb_iv_set(rb_event, "@table_map", rb_table_map);
1202
1320
  rb_iv_set(rb_event, "@rows_flags", USHORT2NUM(e->flags));
@@ -1205,24 +1323,15 @@ rbm2_replication_event_new(rbm2_replication_client_wrapper *wrapper,
1205
1323
  if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
1206
1324
  rb_updated_rows = rb_ary_new();
1207
1325
  }
1208
- const uint8_t *row_data = e->row_data;
1209
- const uint8_t *row_data_end = row_data + e->row_data_size;
1210
1326
  if (!RB_NIL_P(rb_table_map)) {
1211
- VALUE rb_columns = rb_iv_get(rb_table_map, "@columns");
1212
- while (row_data < row_data_end) {
1213
- VALUE rb_row = rbm2_row_parse(&row_data,
1214
- e->column_count,
1215
- column_bitmap,
1216
- rb_columns);
1217
- rb_ary_push(rb_rows, rb_row);
1218
- if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
1219
- VALUE rb_updated_row = rbm2_row_parse(&row_data,
1220
- e->column_count,
1221
- column_update_bitmap,
1222
- rb_columns);
1223
- rb_ary_push(rb_updated_rows, rb_updated_row);
1224
- }
1225
- }
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);
1226
1335
  }
1227
1336
  rb_iv_set(rb_event, "@rows", rb_rows);
1228
1337
  if (klass == rb_cMysql2ReplicationUpdateRowsEvent) {
@@ -1304,9 +1413,13 @@ Init_mysql2_replication(void)
1304
1413
  rb_cDate = rb_const_get(rb_cObject, rb_intern("Date"));
1305
1414
 
1306
1415
  VALUE rb_mMysql2 = rb_const_get(rb_cObject, rb_intern("Mysql2"));
1307
- rb_cMysql2Error = rb_const_get(rb_mMysql2, rb_intern("Error"));
1416
+ rb_eMysql2Error = rb_const_get(rb_mMysql2, rb_intern("Error"));
1308
1417
 
1309
1418
  VALUE rb_mMysql2Replication = rb_define_module("Mysql2Replication");
1419
+ rb_eMysql2ReplicationError =
1420
+ rb_define_class_under(rb_mMysql2Replication,
1421
+ "Error",
1422
+ rb_eStandardError);
1310
1423
 
1311
1424
  rb_cMysql2ReplicationEvent =
1312
1425
  rb_define_class_under(rb_mMysql2Replication, "Event", rb_cObject);
@@ -1,3 +1,3 @@
1
1
  module Mysql2Replication
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.5"
3
3
  end
@@ -35,4 +35,6 @@ Gem::Specification.new do |spec|
35
35
  end
36
36
 
37
37
  spec.add_runtime_dependency("mysql2")
38
+ spec.add_runtime_dependency("native-package-installer")
39
+ spec.add_runtime_dependency("pkg-config")
38
40
  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.1
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: 2021-12-21 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
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: native-package-installer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pkg-config
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
27
55
  description: ''
28
56
  email:
29
57
  - kou@clear-code.com
@@ -62,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
62
90
  - !ruby/object:Gem::Version
63
91
  version: '0'
64
92
  requirements: []
65
- rubygems_version: 3.3.0.dev
93
+ rubygems_version: 3.4.0.dev
66
94
  signing_key:
67
95
  specification_version: 4
68
96
  summary: mysql2-replication is an extension of [mysql2 gem](https://rubygems.org/gems/mysql2).