flydata 0.5.13 → 0.5.14

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
  SHA1:
3
- metadata.gz: d4b03db81cb7465b262dce0c4c8e33a14b5e290b
4
- data.tar.gz: 42c08437e1b5f0d8452f2f2504666d6ce83006a7
3
+ metadata.gz: b2ba68dee697e96ae4e45d7c4ab93da8bfdd0bd9
4
+ data.tar.gz: 5a85b888bf9151233e6163bf825ce52865b5d218
5
5
  SHA512:
6
- metadata.gz: 6de4243e12d2ec8d0c0c62a68a21fd9f1bef9f5a40caebe494687656ab5714d1d88e56ff7aa091796c52a57321e74e6c287ddab02e3968a0029e0203ff3ea47a
7
- data.tar.gz: 910e524b426859dae7e5996bf25148aedf2eebea36decbc602965b483d8cf010ff224e998707c6d35bac7f80036ff0f609ef6dfd88410bf562700d967ad30b34
6
+ metadata.gz: 2ba24a57fee86c3e979c7acf571f73a1d8f12dfc0810f7925d34dd3b7c5d63ddee4d65bc8c2299e204224b93d3a0ab3cfd013dbab3425048e7d1c232328c7658
7
+ data.tar.gz: 0cd58ad653a31e062deb6801bd682cde6940ea2d1c8e8758f72304bd527dbd9549ceaf39ec594f3893f86ca2fa49683b18928ee13bde50b6a2929391df92c6ad
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.13
1
+ 0.5.14
@@ -6,7 +6,7 @@ value:
6
6
  " ", "\t", "\n", "," => :value
7
7
  "'" => :first_char
8
8
  "0" => (mark), :first_zero
9
- [1-9-] => (mark), :number
9
+ [1-9-+\.] => (mark), :number
10
10
  "N" => :null_n
11
11
  ")" => (row_end_callback), :start
12
12
  else => :error
@@ -29,7 +29,7 @@ leading_zero:
29
29
  else => :error
30
30
 
31
31
  number:
32
- [0-9.] => :number
32
+ [0-9.-eE] => :number
33
33
  "," => (value_callback, :end_value)(mark reset), :value
34
34
  ")" => (value_callback, :end_value)(mark reset)(row_end_callback), :start
35
35
  else => :error
@@ -62,7 +62,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
62
62
  } else if (*current == '0') {
63
63
  mark = current; value_len = 1;//mark
64
64
  status = first_zero;
65
- } else if ( (*current >= '1' && *current <= '9') || *current == '-' ) {
65
+ } else if ( (*current >= '1' && *current <= '9') || *current == '-' || *current == '+' || *current == '.') {
66
66
  mark = current; value_len = 1;//mark
67
67
  status = number;
68
68
  } else if (*current == ',') {
@@ -127,7 +127,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
127
127
 
128
128
  case number:
129
129
  if ($DEBUG) std::cout << "number[" << *current << "]: " << std::endl << std::flush;
130
- if ((*current >= '0' && *current <= '9') || *current == '.') {
130
+ if ((*current >= '0' && *current <= '9') || *current == '.' || *current == 'e' || *current == 'E' || *current == '-') {
131
131
  status = number;
132
132
  } else if (*current == ',') {
133
133
  ch.value_callback(mark, value_len - 1, true);//value_callback :end_value
@@ -389,10 +389,12 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
389
389
  ch.value_callback("\x1a", 1, false);//value_callback '\Z'
390
390
  mark = 0; value_len = 0;
391
391
  status = first_char;
392
- } else if (*current == '0') {
393
- ch.value_callback("\0", 1, false);//value_callback '\0'
394
- mark = 0; value_len = 0;
395
- status = first_char;
392
+ // Disabled handling of \0 for now in order to keep it compatible with the old
393
+ // implementation.
394
+ // } else if (*current == '0') {
395
+ // ch.value_callback("\0", 1, false);//value_callback '\0'
396
+ // mark = 0; value_len = 0;
397
+ // status = first_char;
396
398
  } else {
397
399
  status = following_char;
398
400
  }
@@ -51,9 +51,10 @@ module FlydataCore
51
51
  default_option = nil if default_option == ''
52
52
 
53
53
  custom_option = option[:custom_option]
54
+ custom_option_end = option[:custom_option_end] # put in the end of the command
54
55
 
55
56
  [command, host, port, username, password, default_option,
56
- custom_option, database, tables].compact.join(' ')
57
+ custom_option, database, tables, custom_option_end].compact.join(' ')
57
58
  end
58
59
 
59
60
  # DDL_DUMP_CMD_TEMPLATE = "MYSQL_PWD=\"%s\" mysqldump --protocol=tcp -d -h %s -P %s -u %s %s %s"
@@ -114,6 +114,13 @@ module FlydataCore
114
114
  'mysql -h test-host -P 3306 -utestuser -ptestpassword --default-character-set=utf8 --protocol=tcp --skip-auto-rehash -e "SHOW GRANTS;" testdb'
115
115
  ) }
116
116
  end
117
+
118
+ context 'when custom_option_end is set' do
119
+ before { option[:custom_option_end] = 'test_table' }
120
+ it { is_expected.to eq(
121
+ 'mysqldump -h test-host -P 3306 -utestuser -ptestpassword --default-character-set=utf8 --protocol=tcp testdb test_table'
122
+ ) }
123
+ end
117
124
  end
118
125
 
119
126
  describe '.generate_mysql_ddl_dump_cmd' do
data/flydata.gemspec CHANGED
Binary file
@@ -1,38 +1,10 @@
1
- require 'open3'
2
1
  require 'flydata/command/sync'
3
- require 'flydata-core/mysql/command_generator'
2
+ require 'flydata/command/mysql_command_base'
4
3
 
5
4
  module Flydata
6
5
  module Command
7
-
8
6
  class Mysql < Sync
9
- def run
10
- de = retrieve_sync_data_entry
11
- de['mysql_data_entry_preference'].delete('tables')
12
- cmd = FlydataCore::Mysql::CommandGenerator::generate_mysql_cmd(de['mysql_data_entry_preference'])
13
- if $stdin.tty?
14
- # interactive shell
15
- system cmd
16
- else
17
- # execute queries given to $stdin
18
- Open3.popen2e(cmd) do |i, o, wt|
19
- $stdin.each_line do |line|
20
- i.print line
21
- end
22
- i.close
23
- while line = o.gets
24
- print line
25
- end
26
- end
27
- end
28
- end
29
-
30
- def flush; end
31
- def reset; end
32
- def skip; end
33
- def generate_table_ddl; end
34
- def fix_binlogpos; end
7
+ include MysqlCommandBase
35
8
  end
36
-
37
9
  end
38
10
  end
@@ -0,0 +1,46 @@
1
+ require 'open3'
2
+ require 'flydata-core/mysql/command_generator'
3
+
4
+ module Flydata
5
+ module Command
6
+
7
+ module MysqlCommandBase
8
+ def run(*args)
9
+ de = retrieve_sync_data_entry
10
+ cmd = generate_command(de['mysql_data_entry_preference'], args)
11
+ return if cmd.to_s.empty?
12
+ $stderr.puts "command:#{cmd}" if FLYDATA_DEBUG
13
+ if $stdin.tty?
14
+ # interactive shell
15
+ system cmd
16
+ else
17
+ # execute queries given to $stdin
18
+ Open3.popen2e(cmd) do |i, o, wt|
19
+ $stdin.each_line do |line|
20
+ i.print line
21
+ end
22
+ i.close
23
+ while line = o.gets
24
+ print line
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def generate_command(dbconf, args)
31
+ dbconf.delete('tables')
32
+ dbconf[:custom_option_end] = args.join(' ')
33
+ FlydataCore::Mysql::CommandGenerator::generate_mysql_cmd(dbconf)
34
+ end
35
+
36
+ def flush; end
37
+ def reset; end
38
+ def skip; end
39
+ def generate_table_ddl; end
40
+ def fix_binlogpos; end
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+
@@ -0,0 +1,33 @@
1
+ require 'flydata/command/sync'
2
+ require 'flydata/command/mysql_command_base'
3
+
4
+ module Flydata
5
+ module Command
6
+ class Mysqlbinlog < Sync
7
+ include MysqlCommandBase
8
+
9
+ def generate_command(dbconf, args)
10
+ dbconf.delete('tables')
11
+ dbconf[:custom_option_end] = args.join(' ')
12
+ dbconf[:command] = 'mysqlbinlog'
13
+ # --default-character-set=utf8 is not supported
14
+ dbconf[:no_default_option] = true
15
+ # ssl is not supported for mysql5.6 or older mysqlbinlog command
16
+ dbconf.delete('ssl_ca')
17
+ dbconf.delete('ssl_cipher')
18
+ dbconf.delete('database')
19
+ if args.empty?
20
+ puts <<EOT
21
+ example:
22
+ 1. Dump raw binlog
23
+ flydata mysqlbinlog --raw --read-from-remote-server --result-file "binlog-" mysql-bin-changelog.xxxx
24
+ 2. Dump decoded binlog data
25
+ flydata mysqlbinlog -vv --base64-output=decode-row --hexdump --read-from-remote-server --start-position=4 --stop-position=yyyyy mysql-bin-changelog.xxxxx > mysql-bin-changelog.xxxxx
26
+ EOT
27
+ return
28
+ end
29
+ FlydataCore::Mysql::CommandGenerator::generate_mysql_cmd(dbconf)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ require 'flydata/command/sync'
2
+ require 'flydata/command/mysql_command_base'
3
+
4
+ module Flydata
5
+ module Command
6
+ class Mysqldump < Sync
7
+ include MysqlCommandBase
8
+
9
+ def generate_command(dbconf, args)
10
+ dbconf.delete('tables')
11
+ dbconf[:custom_option_end] = args.join(' ')
12
+ dbconf[:command] = 'mysqldump'
13
+ FlydataCore::Mysql::CommandGenerator::generate_mysql_cmd(dbconf)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -18,7 +18,7 @@ require 'flydata-core/table_def'
18
18
  require 'flydata-core/mysql/binlog_pos'
19
19
  require 'flydata/mysql/table_ddl'
20
20
  require 'flydata-core/mysql/command_generator'
21
- #require 'ruby-prof'
21
+ #require 'ruby-prof' # to enable profiling, also set the class' RUN_PROFILE
22
22
 
23
23
  module Flydata
24
24
  module Command
@@ -26,6 +26,8 @@ module Flydata
26
26
  class Sync < Base
27
27
  include Helpers
28
28
 
29
+ RUN_PROFILE = false
30
+
29
31
  INSERT_PROGRESS_INTERVAL = 1000
30
32
  SERVER_DATA_PROCESSING_TIMEOUT = 3600 # seconds
31
33
 
@@ -784,6 +786,7 @@ EOM
784
786
 
785
787
  begin
786
788
  threads = []
789
+ RubyProf.start if RUN_PROFILE and defined?(RubyProf) and not RubyProf.running?
787
790
  Flydata::Parser::Mysql::MysqlDumpParser.new(option).parse(
788
791
  mysqldump_io,
789
792
  # create table
@@ -792,12 +795,13 @@ EOM
792
795
  # dump mysql_table for resume
793
796
  #TODO: make it option
794
797
  sync_fm.save_mysql_table_marshal_dump(mysql_table)
798
+ mysql_table.set_value_converters(FlydataCore::TableDef::MysqlTableDef::VALUE_CONVERTERS)
795
799
  },
796
800
  # insert record
797
801
  Proc.new { |mysql_table, values_set|
798
802
  mysql_table_name = mysql_table.table_name
799
803
  records = values_set.collect do |values|
800
- values = convert_to_flydata_values(mysql_table, values)
804
+ convert_to_flydata_values(mysql_table, values)
801
805
  json = JSON.generate_kv_pairs(mysql_table.column_names, values)
802
806
  {table_name: mysql_table_name, log: json}
803
807
  end
@@ -839,6 +843,14 @@ EOM
839
843
  ee.description = " Please contact support@flydata.com to report the issue."
840
844
  ee.set_backtrace e.backtrace
841
845
  raise ee
846
+ ensure
847
+ if RUN_PROFILE and defined?(RubyProf) and RubyProf.running?
848
+ result = RubyProf.stop
849
+ #printer = RubyProf::GraphPrinter.new(result)
850
+ printer = RubyProf::GraphHtmlPrinter.new(result)
851
+ #printer.print(STDOUT)
852
+ printer.print(File.new("ruby-prof-out-#{Time.now.to_i}.html", "w"), :min_percent => 3)
853
+ end
842
854
  end
843
855
  forwarder.close
844
856
  log_info_stdout(" -> Done")
@@ -985,15 +997,12 @@ EOM
985
997
  end
986
998
 
987
999
  def convert_to_flydata_values(mysql_table, values)
988
- types = mysql_table.format_types
989
- sz = types.size
990
- result = []
991
- i = 0
992
- while i < sz
993
- result << FlydataCore::TableDef::MysqlTableDef.convert_to_flydata_value(values[i], types[i])
994
- i += 1
1000
+ vc = mysql_table.value_converters
1001
+ return if vc.empty?
1002
+
1003
+ vc.each_pair do |index, converter|
1004
+ values[index] = converter.call(values[index])
995
1005
  end
996
- result
997
1006
  end
998
1007
 
999
1008
  def generate_json(column_names, values)
@@ -3,6 +3,7 @@ require 'io/wait'
3
3
  require 'mysql2'
4
4
  require 'flydata-core/mysql/config'
5
5
  require 'flydata-core/mysql/command_generator'
6
+ #require 'ruby-prof' # to enable profiling, also set the class' RUN_PROFILE
6
7
 
7
8
  module Flydata
8
9
  module Parser
@@ -33,18 +34,26 @@ module Flydata
33
34
  @table_name = table_name
34
35
  @columns = columns
35
36
  @column_names = columns.collect{|k,v| v[:column_name]}
36
- @format_types = columns.collect{|k,v| v[:format_type]}
37
37
  @primary_keys = primary_keys
38
+ @value_converters = {}
38
39
  end
39
40
 
40
- attr_accessor :table_name, :columns, :column_names, :format_types,
41
- :primary_keys
41
+ attr_accessor :table_name, :columns, :column_names, :primary_keys
42
+ attr_reader :value_converters
42
43
 
43
44
  def add_column(column)
44
45
  cn = column[:column_name]
45
46
  @columns[cn] = column
46
47
  @column_names << cn
47
- @format_types << column[:format_type]
48
+ end
49
+
50
+ def set_value_converters(converter_hash)
51
+ @columns.each_with_index do |(k, v), i|
52
+ type = v[:format_type]
53
+ if converter_hash.has_key?(type)
54
+ @value_converters[i] = converter_hash[type]
55
+ end
56
+ end
48
57
  end
49
58
  end
50
59
 
@@ -475,12 +484,14 @@ EOS
475
484
  class InsertParser
476
485
  #INSERT INTO `data_entries` VALUES (2,2,'access_log'), (2,3,'access_log2');
477
486
 
487
+ RUN_PROFILE = false
488
+
478
489
  def start_ruby_prof
479
- RubyProf.start if defined?(RubyProf) and not RubyProf.running?
490
+ RubyProf.start if RUN_PROFILE and defined?(RubyProf) and not RubyProf.running?
480
491
  end
481
492
 
482
493
  def stop_ruby_prof
483
- if defined?(RubyProf) and RubyProf.running?
494
+ if RUN_PROFILE and defined?(RubyProf) and RubyProf.running?
484
495
  result = RubyProf.stop
485
496
  #printer = RubyProf::GraphPrinter.new(result)
486
497
  printer = RubyProf::GraphHtmlPrinter.new(result)
@@ -254,6 +254,10 @@ module Flydata
254
254
  subject { subject_object.send(:convert_to_flydata_values, mysql_table, values) }
255
255
  let(:values) { [4, 'John', nil, col4_value, nil, nil] }
256
256
 
257
+ before do
258
+ mysql_table.set_value_converters(FlydataCore::TableDef::MysqlTableDef::VALUE_CONVERTERS)
259
+ end
260
+
257
261
  context 'with binary column' do
258
262
  let(:col4_type) { "binary" }
259
263
  let(:col4_width) { 5 }
@@ -263,7 +267,8 @@ module Flydata
263
267
  it 'truncates trailing "0" if the type is binary' do
264
268
  expected_values = values.dup
265
269
  expected_values[3] = truncated_binary
266
- is_expected.to eq expected_values
270
+ subject
271
+ expect(values).to eq expected_values
267
272
  end
268
273
  end
269
274
  end
@@ -818,11 +818,9 @@ EOT
818
818
  context 'with a single escape char' do
819
819
  let(:value) { %q|\\0| }
820
820
  #let(:expected_value) { %Q|\0| }
821
- #it 'returns correct chars' do
822
- # expect(subject).to eq([[expected_value]])
823
- #end
824
- it 'returns an error (for now)' do
825
- expect{subject}.to raise_error(ArgumentError)
821
+ let(:expected_value) { value } # this is compatible with the previous implementation but it's actually wrong. For now, keeping it as is because allowing the null character in a string could open a can of worms.
822
+ it 'returns correct chars' do
823
+ expect(subject).to eq([[expected_value]])
826
824
  end
827
825
  end
828
826
  context 'with an escape char followed by a regular char' do
@@ -974,6 +972,49 @@ EOT
974
972
  end
975
973
  end
976
974
 
975
+ context 'when a scientific number is given' do
976
+ let(:target_line) {"INSERT INTO `test_table` VALUES (1,#{num_str});"}
977
+ shared_examples "accepting the value as is" do
978
+ it 'should accept the value as is' do
979
+ expect(subject).to eq([['1', num_str]])
980
+ end
981
+ end
982
+ context 'capital E' do
983
+ let(:num_str) { '1.2E3' }
984
+ it_behaves_like "accepting the value as is"
985
+ end
986
+ context 'lowercase e' do
987
+ let(:num_str) { '1.2e3' }
988
+ it_behaves_like "accepting the value as is"
989
+ end
990
+ context 'negative integer' do
991
+ let(:num_str) { '-1.2e3' }
992
+ it_behaves_like "accepting the value as is"
993
+ end
994
+ context 'negative fractional' do
995
+ let(:num_str) { '1.2e-3' }
996
+ it_behaves_like "accepting the value as is"
997
+ end
998
+ context 'negative integer & fractional' do
999
+ let(:num_str) { '-1.2e-3' }
1000
+ it_behaves_like "accepting the value as is"
1001
+ end
1002
+ end
1003
+
1004
+ context 'when a number with positive sign is given' do
1005
+ let(:target_line) {"INSERT INTO `test_table` VALUES (1,+9.10);"}
1006
+ it 'should accept the value as is' do
1007
+ expect(subject).to eq([['1', '+9.10']])
1008
+ end
1009
+ end
1010
+
1011
+ context 'when a number with no leading zero is given' do
1012
+ let(:target_line) {"INSERT INTO `test_table` VALUES (1,.10);"}
1013
+ it 'should accept the value as is' do
1014
+ expect(subject).to eq([['1', '.10']])
1015
+ end
1016
+ end
1017
+
977
1018
  context 'when 0.00 is given' do
978
1019
  let(:target_line) {"INSERT INTO `test_table` VALUES (1,0.00);"}
979
1020
  it 'should not remove the leading zeros' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flydata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.13
4
+ version: 0.5.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Koichi Fujikawa
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-10-26 00:00:00.000000000 Z
15
+ date: 2015-10-28 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rest-client
@@ -582,6 +582,9 @@ files:
582
582
  - lib/flydata/command/kill_all.rb
583
583
  - lib/flydata/command/login.rb
584
584
  - lib/flydata/command/mysql.rb
585
+ - lib/flydata/command/mysql_command_base.rb
586
+ - lib/flydata/command/mysqlbinlog.rb
587
+ - lib/flydata/command/mysqldump.rb
585
588
  - lib/flydata/command/restart.rb
586
589
  - lib/flydata/command/routine.rb
587
590
  - lib/flydata/command/sender.rb