flydata 0.6.4 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/flydata-core/lib/flydata-core/table_def/base.rb +31 -0
- data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +9 -30
- data/flydata-core/lib/flydata-core/table_def/postgresql_table_def.rb +111 -0
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +4 -1
- data/flydata-core/spec/table_def/postgresql_table_def_spec.rb +348 -0
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +25 -0
- data/flydata.gemspec +0 -0
- data/lib/flydata.rb +0 -7
- data/lib/flydata/command/base.rb +3 -2
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/base.rb +5 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/flush_support.rb +52 -0
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/flydata_sync.rb +55 -0
- data/lib/flydata/fluent-plugins/{idle_event_detector.rb → flydata_plugin_ext/idle_event_detector.rb} +0 -0
- data/lib/flydata/fluent-plugins/{preference.rb → flydata_plugin_ext/preference.rb} +2 -14
- data/lib/flydata/fluent-plugins/flydata_plugin_ext/transaction_support.rb +58 -0
- data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +55 -135
- data/lib/flydata/fluent-plugins/mysql/dml_record_handler.rb +9 -4
- data/lib/flydata/helper/server.rb +7 -0
- data/lib/flydata/preference/data_entry_preference.rb +5 -13
- data/lib/flydata/source.rb +1 -1
- data/lib/flydata/source/data_entry.rb +29 -0
- data/lib/flydata/source/sync.rb +19 -0
- data/lib/flydata/source/sync_generate_table_ddl.rb +47 -7
- data/lib/flydata/source_mysql/data_entry.rb +22 -0
- data/lib/flydata/source_mysql/parser/dump_parser.rb +1 -1
- data/lib/flydata/source_mysql/parser/mysql_alter_table.treetop +8 -3
- data/lib/flydata/source_mysql/sync.rb +1 -8
- data/lib/flydata/source_mysql/sync_generate_table_ddl.rb +11 -16
- data/lib/flydata/source_postgresql/data_entry.rb +21 -0
- data/lib/flydata/source_postgresql/sync.rb +29 -0
- data/lib/flydata/source_postgresql/sync_generate_table_ddl.rb +126 -0
- data/spec/flydata/fluent-plugins/{idle_event_detector_spec.rb → flydata_plugin_ext/idle_event_detector_spec.rb} +1 -1
- data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +10 -0
- data/spec/flydata/source_mysql/parser/alter_table_parser_spec.rb +119 -0
- data/spec/flydata/source_mysql/parser/dump_parser_spec.rb +32 -1
- data/spec/flydata/source_mysql/sync_generate_table_ddl_spec.rb +4 -4
- metadata +31 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 614092c4a27b51744d8f8fdbd521e95205455eac
|
4
|
+
data.tar.gz: 3e6d10c8acd5331700c312c1982a6a9acdba3c66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0370a93f87eedacf8b56210c15363be7f040980b73eb938cf077953a16d0da942d522881601e21ded8a89a1376c480263483a61d4b0932cd41b70739c457f964
|
7
|
+
data.tar.gz: d870e1abfe9491ad135b1b8ee4e45a293b8a312db2823b7a1cc73fd7d337d19a47e68935c2b6fa606a1f0b2a95af87e7c0ee350170192638b109e75acf567647
|
data/Gemfile
CHANGED
@@ -9,6 +9,7 @@ gem "highline", '~> 1.6', '>= 1.6.19'
|
|
9
9
|
gem "fluentd", "0.10.46"
|
10
10
|
gem "fluent-plugin-mysql-binlog", '~> 0.0', '>= 0.0.2'
|
11
11
|
gem "mysql2", '~> 0.3', '>= 0.3.17'
|
12
|
+
gem "pg", '~> 0.18.4'
|
12
13
|
gem "slop", '~> 3.4', '>= 3.4.6'
|
13
14
|
gem "treetop", '~> 1.5', '>= 1.5.3'
|
14
15
|
gem "sys-filesystem", '~> 1.1', '>= 1.1.3'
|
data/Gemfile.lock
CHANGED
@@ -79,6 +79,7 @@ GEM
|
|
79
79
|
multi_json (~> 1.3)
|
80
80
|
multi_xml (~> 0.5)
|
81
81
|
rack (~> 1.2)
|
82
|
+
pg (0.18.4)
|
82
83
|
polyglot (0.3.5)
|
83
84
|
protected_attributes (1.0.8)
|
84
85
|
activemodel (>= 4.0.1, < 5.0)
|
@@ -139,6 +140,7 @@ DEPENDENCIES
|
|
139
140
|
json (~> 1.8, >= 1.8.0)
|
140
141
|
kodama (~> 0.1, >= 0.1.8)
|
141
142
|
mysql2 (~> 0.3, >= 0.3.17)
|
143
|
+
pg (~> 0.18.4)
|
142
144
|
protected_attributes (~> 1.0, >= 1.0.8)
|
143
145
|
pry
|
144
146
|
rake-compiler (~> 0.9, >= 0.9.5)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.5
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module FlydataCore
|
2
|
+
module TableDef
|
3
|
+
|
4
|
+
class Base
|
5
|
+
def initialize(table_def, table_name, columns, column_def, default_charset,
|
6
|
+
default_source_charset, comment)
|
7
|
+
@table_def = table_def
|
8
|
+
@table_name = table_name
|
9
|
+
@columns = columns
|
10
|
+
@column_def = column_def
|
11
|
+
@default_charset = default_charset
|
12
|
+
@default_source_charset = default_source_charset
|
13
|
+
@comment = comment
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :columns, :column_def, :table_name, :default_source_charset
|
17
|
+
|
18
|
+
def to_flydata_tabledef
|
19
|
+
tabledef = { table_name: @table_name,
|
20
|
+
columns: @columns,
|
21
|
+
}
|
22
|
+
tabledef[:default_charset] = @default_charset if @default_charset
|
23
|
+
tabledef[:comment] = @comment if @comment
|
24
|
+
tabledef[:src_ddl] = @table_def
|
25
|
+
|
26
|
+
tabledef
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
require 'flydata-core/table_def/base'
|
2
|
+
|
1
3
|
module FlydataCore
|
2
4
|
module TableDef
|
3
5
|
|
4
|
-
class MysqlTableDef
|
6
|
+
class MysqlTableDef < Base
|
5
7
|
# Check and set the varchar(char) size which is converted from
|
6
8
|
# length to byte size.
|
7
9
|
# On Mysql the record size of varchar(char) is a length of characters.
|
8
10
|
# ex) varchar(6) on mysql -> varchar(18) on flydata
|
9
11
|
PROC_override_varchar = ->(type, mysql_type, flydata_type) do
|
10
12
|
return type unless %w(char varchar).include?(mysql_type)
|
11
|
-
if type =~ /\((\d
|
13
|
+
if type =~ /\((\s*\d+\s*)\)/
|
12
14
|
# expect 3 byte UTF-8 character
|
13
15
|
"#{flydata_type}(#{$1.to_i * 3})"
|
14
16
|
else
|
@@ -18,7 +20,7 @@ class MysqlTableDef
|
|
18
20
|
|
19
21
|
PROC_override_varbinary = ->(type, mysql_type, flydata_type) do
|
20
22
|
return type unless %w(binary varbinary).include?(mysql_type)
|
21
|
-
if type =~ /\((\d+)\)/
|
23
|
+
if type =~ /\((\s*\d+\s*)\)/ ###DEBUG/\((\d+)\)/
|
22
24
|
# expect 2 bytes for each original byte + 2 bytes for the prefix
|
23
25
|
# ex) 4E5DFF => "0x4e5dff"
|
24
26
|
"#{flydata_type}(#{$1.to_i * 2 + 2})"
|
@@ -87,24 +89,13 @@ class MysqlTableDef
|
|
87
89
|
params ? self.new(*params) : nil
|
88
90
|
end
|
89
91
|
|
90
|
-
def initialize(table_def, table_name, columns, column_def, default_charset,
|
91
|
-
default_charset_mysql, comment)
|
92
|
-
@table_def = table_def
|
93
|
-
@table_name = table_name
|
94
|
-
@columns = columns
|
95
|
-
@column_def = column_def
|
96
|
-
@default_charset = default_charset
|
97
|
-
@default_charset_mysql = default_charset_mysql
|
98
|
-
@comment = comment
|
99
|
-
end
|
100
|
-
|
101
92
|
def self._create(io, options)
|
102
93
|
table_def = ''
|
103
94
|
table_name = nil
|
104
95
|
columns = []
|
105
96
|
column_def = {}
|
106
97
|
default_charset = nil
|
107
|
-
|
98
|
+
default_source_charset = nil
|
108
99
|
comment = nil
|
109
100
|
|
110
101
|
position = :before_create_table
|
@@ -135,8 +126,8 @@ class MysqlTableDef
|
|
135
126
|
#) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test table';
|
136
127
|
elsif stripped_line.start_with?(')')
|
137
128
|
if line =~ /DEFAULT CHARSET\s*=\s*([a-z0-9]+)/
|
138
|
-
|
139
|
-
default_charset = flydata_charset(
|
129
|
+
default_source_charset = $1
|
130
|
+
default_charset = flydata_charset(default_source_charset)
|
140
131
|
end
|
141
132
|
comment = $1 if /COMMENT='((?:\\'|[^'])*)'/.match(line)
|
142
133
|
position = :after_create_table
|
@@ -157,21 +148,9 @@ class MysqlTableDef
|
|
157
148
|
break
|
158
149
|
end
|
159
150
|
end
|
160
|
-
position == :after_create_table ? [table_def, table_name, columns, column_def, default_charset,
|
151
|
+
position == :after_create_table ? [table_def, table_name, columns, column_def, default_charset, default_source_charset, comment] : nil
|
161
152
|
end
|
162
|
-
attr_reader :columns, :column_def, :table_name, :default_charset_mysql
|
163
153
|
|
164
|
-
def to_flydata_tabledef
|
165
|
-
tabledef = { table_name: @table_name,
|
166
|
-
columns: @columns,
|
167
|
-
}
|
168
|
-
tabledef[:default_charset] = @default_charset if @default_charset
|
169
|
-
tabledef[:comment] = @comment if @comment
|
170
|
-
tabledef[:src_ddl] = @table_def
|
171
|
-
|
172
|
-
tabledef
|
173
|
-
end
|
174
|
-
|
175
154
|
# Replaces a MySQL string with an empty string ('')
|
176
155
|
def self.strip_string(line)
|
177
156
|
line.gsub(/'(\\'|''|[^'])*'/, "''")
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'flydata-core/table_def/base'
|
2
|
+
|
3
|
+
module FlydataCore
|
4
|
+
module TableDef
|
5
|
+
|
6
|
+
class PostgresqlTableDef < Base
|
7
|
+
|
8
|
+
VALUE_CONVERTERS = {}
|
9
|
+
|
10
|
+
TYPE_MAP_P2F = {
|
11
|
+
'bigint' => {type: 'int8'},
|
12
|
+
'character varying' => {type: 'varchar',
|
13
|
+
width_attrs:["character_octet_length"]}, # TODO check def_width
|
14
|
+
'integer' => {type: 'int4'},
|
15
|
+
'timestamp with time zone' => {type: 'datetime'}, # TODO may need override?
|
16
|
+
'timestamp without time zone' => {type: 'datetime'}, # TODO may need override?
|
17
|
+
'bytea' => {type: 'varbinary'}, # TODO need value conversion
|
18
|
+
'numeric' => {type: 'numeric',
|
19
|
+
width_attrs:["numeric_precision", "numeric_scale"],
|
20
|
+
def_width:[nil, 0],
|
21
|
+
},
|
22
|
+
# TODO add more types
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.convert_to_flydata_type(information_schema_columns)
|
26
|
+
pg_type = information_schema_columns["data_type"]
|
27
|
+
unless TYPE_MAP_P2F.has_key?(pg_type)
|
28
|
+
raise "Unknown PostgreSQL type or internal error. type:#{pg_type}"
|
29
|
+
end
|
30
|
+
type_hash = TYPE_MAP_P2F[pg_type]
|
31
|
+
flydata_type = type_hash[:type]
|
32
|
+
ret_type = flydata_type
|
33
|
+
|
34
|
+
width_values = get_width_values(information_schema_columns, type_hash)
|
35
|
+
if width_values
|
36
|
+
ret_type += "(#{width_values.join(",")})"
|
37
|
+
end
|
38
|
+
|
39
|
+
if type_hash[:override]
|
40
|
+
ret_type = type_hash[:override].call(ret_type, pg_type, flydata_type)
|
41
|
+
end
|
42
|
+
ret_type
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.create(information_schema_columns, options)
|
46
|
+
params = _create(information_schema_columns, options)
|
47
|
+
params ? self.new(*params) : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def self.get_width_values(information_schema_columns, type_hash)
|
53
|
+
values = []
|
54
|
+
if type_hash.has_key?(:width_attrs)
|
55
|
+
values = type_hash[:width_attrs].collect{|attr| information_schema_columns[attr] }
|
56
|
+
end
|
57
|
+
|
58
|
+
if type_hash.has_key?(:def_width)
|
59
|
+
if values.nil? || values.size != type_hash[:def_width].size
|
60
|
+
raise "The number of the default values must match the number of width attributes def_width:#{type_hash[:def_width].inspect} width_attrs:#{type_hash[:width_attrs].inspect}"
|
61
|
+
end
|
62
|
+
values = values.each_with_index.collect {|v, i| v ? v : type_hash[:def_width][i]}
|
63
|
+
end
|
64
|
+
values.pop until values.empty? || values.last # remove trailing nil
|
65
|
+
if values.any?{|v| v.nil?}
|
66
|
+
raise "nil value is not allowed"
|
67
|
+
end
|
68
|
+
values.empty? ? nil : values
|
69
|
+
end
|
70
|
+
|
71
|
+
def self._create(information_schema_columns, options)
|
72
|
+
table_def = information_schema_columns.inspect
|
73
|
+
table_name = nil
|
74
|
+
columns = []
|
75
|
+
column_def = {}
|
76
|
+
# SourcePostgresql uses UTF8 client encoding no matter what the server
|
77
|
+
# encoding is.
|
78
|
+
default_charset = 'UTF_8'
|
79
|
+
default_charset_postgresql = 'UTF8'
|
80
|
+
comment = nil
|
81
|
+
|
82
|
+
information_schema_columns.each do |iscol|
|
83
|
+
column = parse_one_column_def(iscol)
|
84
|
+
if table_name
|
85
|
+
unless table_name == column[:table]
|
86
|
+
raise "Table name must match through all columns. Got `#{table_name}` and `#{column[:table]}`"
|
87
|
+
end
|
88
|
+
else
|
89
|
+
table_name = column[:table]
|
90
|
+
end
|
91
|
+
columns << column
|
92
|
+
coldef = iscol.inspect
|
93
|
+
column_def[column[:column]] = coldef
|
94
|
+
end
|
95
|
+
[table_def, table_name, columns, column_def, default_charset, default_charset_postgresql, comment]
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.parse_one_column_def(information_schema_column)
|
99
|
+
column = {}
|
100
|
+
column[:table] = information_schema_column["table_name"]
|
101
|
+
column[:column] = information_schema_column["column_name"]
|
102
|
+
column[:type] = convert_to_flydata_type(information_schema_column)
|
103
|
+
column[:not_null] = true if information_schema_column["is_nullable"] == "NO"
|
104
|
+
column[:primary_key] = true if information_schema_column["is_primary"]
|
105
|
+
column[:default] = information_schema_column["column_default"] # TODO nill handling
|
106
|
+
column
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -229,7 +229,7 @@ EOS
|
|
229
229
|
|
230
230
|
if (column.has_key?(:default))
|
231
231
|
val = replace_default_value(type, type_info[:type], column[:default])
|
232
|
-
line += " DEFAULT #{val}"
|
232
|
+
line += " DEFAULT #{val}" if val
|
233
233
|
elsif not_null && opt[:for] == :alter_table
|
234
234
|
# Redshift doesn't allow adding a not null column without default value
|
235
235
|
# Add a defalt value
|
@@ -275,6 +275,9 @@ EOS
|
|
275
275
|
default_value.oct
|
276
276
|
elsif /^'.*'$/.match(default_value)
|
277
277
|
default_value
|
278
|
+
elsif /\s*nextval\(/.match(default_value)
|
279
|
+
# Redshift does not support nextval() function. Set no default.
|
280
|
+
nil
|
278
281
|
else
|
279
282
|
"'#{default_value}'"
|
280
283
|
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'flydata-core/table_def/postgresql_table_def'
|
3
|
+
|
4
|
+
module FlydataCore
|
5
|
+
module TableDef
|
6
|
+
|
7
|
+
describe PostgresqlTableDef do
|
8
|
+
let(:subject_object) {
|
9
|
+
described_class.new(table_def, table_name, columns, column_def,
|
10
|
+
default_charset, default_charset_postgresql, comment)
|
11
|
+
}
|
12
|
+
|
13
|
+
let(:table_def) { double('table_def') }
|
14
|
+
let(:table_name) { double('table_name') }
|
15
|
+
let(:columns) { double('columns') }
|
16
|
+
let(:column_def) { double('column_def') }
|
17
|
+
let(:default_charset) { double('default_charset') }
|
18
|
+
let(:default_charset_postgresql) { double('default_charset_postgresql') }
|
19
|
+
let(:comment) { double('comment') }
|
20
|
+
|
21
|
+
let(:information_schema_columns) { {} }
|
22
|
+
|
23
|
+
describe '.convert_to_flydata_type' do
|
24
|
+
subject { described_class.convert_to_flydata_type(information_schema_columns) }
|
25
|
+
|
26
|
+
before do
|
27
|
+
information_schema_columns["data_type"] = data_type
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:type_hash) { double('type_hash') }
|
31
|
+
let(:numeric_precision) { nil }
|
32
|
+
let(:numeric_scale) { nil }
|
33
|
+
let(:width_values) do
|
34
|
+
a = [ numeric_precision, numeric_scale ]
|
35
|
+
a.pop until a.empty? || a.last
|
36
|
+
a.empty? ? nil : a
|
37
|
+
end
|
38
|
+
before do
|
39
|
+
allow(described_class).to receive(:get_width_values).
|
40
|
+
with(information_schema_columns, type_hash).
|
41
|
+
and_return(width_values)
|
42
|
+
end
|
43
|
+
|
44
|
+
context "with data type numeric" do
|
45
|
+
let(:data_type) { "numeric" }
|
46
|
+
|
47
|
+
before do
|
48
|
+
information_schema_columns["numeric_precision"] = numeric_precision
|
49
|
+
information_schema_columns["numeric_scale"] = numeric_scale
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:type_hash) { PostgresqlTableDef::TYPE_MAP_P2F[data_type] }
|
53
|
+
|
54
|
+
context "with precision nil" do
|
55
|
+
let(:numeric_precision) { nil }
|
56
|
+
context "with scale nil" do
|
57
|
+
let(:numeric_scale) { nil }
|
58
|
+
it { is_expected.to eq "numeric" }
|
59
|
+
end
|
60
|
+
context "with scale 2" do
|
61
|
+
let(:numeric_scale) { 2 }
|
62
|
+
it do
|
63
|
+
expect(described_class).to receive(:get_width_values).
|
64
|
+
with(information_schema_columns, type_hash).and_raise("test")
|
65
|
+
|
66
|
+
expect{subject}.to raise_error("test")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
context "with precision 23" do
|
71
|
+
let(:numeric_precision) { 23 }
|
72
|
+
context "with scale nil" do
|
73
|
+
let(:numeric_scale) { nil }
|
74
|
+
it { is_expected.to eq "numeric(23)" }
|
75
|
+
end
|
76
|
+
context "with scale 2" do
|
77
|
+
let(:numeric_scale) { 2 }
|
78
|
+
it { is_expected.to eq "numeric(23,2)" }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
# TODO Add data type specific specs here
|
83
|
+
context "with unknown data type" do
|
84
|
+
let(:data_type) { "duck" }
|
85
|
+
it { expect{subject}.to raise_error /Unknown PostgreSQL type/ }
|
86
|
+
end
|
87
|
+
context "with no data type" do
|
88
|
+
let(:data_type) { nil }
|
89
|
+
it { expect{subject}.to raise_error /Unknown PostgreSQL type/ }
|
90
|
+
end
|
91
|
+
context "with test data type" do
|
92
|
+
let(:data_type) { test_data_type }
|
93
|
+
|
94
|
+
before do
|
95
|
+
allow(PostgresqlTableDef::TYPE_MAP_P2F).to receive(:has_key?).
|
96
|
+
with(test_data_type).and_return true
|
97
|
+
allow(PostgresqlTableDef::TYPE_MAP_P2F).to receive(:[]).
|
98
|
+
with(test_data_type).and_return test_type_hash
|
99
|
+
end
|
100
|
+
let(:test_data_type) { double('test_data_type') }
|
101
|
+
|
102
|
+
let(:type_hash) { test_type_hash }
|
103
|
+
let(:test_type_hash) { {type: test_fd_type} }
|
104
|
+
let(:test_fd_type) { "testfdtype" }
|
105
|
+
|
106
|
+
let(:override_proc) { double('override_proc') }
|
107
|
+
let(:overriden_type) { double('overriden_type') }
|
108
|
+
|
109
|
+
context "no width values" do
|
110
|
+
let(:width_values) { nil }
|
111
|
+
|
112
|
+
it { is_expected.to eq test_fd_type }
|
113
|
+
end
|
114
|
+
context "single width value" do
|
115
|
+
let(:width_values) { [10] }
|
116
|
+
|
117
|
+
it { is_expected.to eq "#{test_fd_type}(10)" }
|
118
|
+
end
|
119
|
+
context "two width values" do
|
120
|
+
let(:width_values) { [10,2] }
|
121
|
+
|
122
|
+
it { is_expected.to eq "#{test_fd_type}(10,2)"}
|
123
|
+
end
|
124
|
+
context "with override proc" do
|
125
|
+
before do
|
126
|
+
test_type_hash[:override] = override_proc
|
127
|
+
end
|
128
|
+
it 'calls the override proc of the type and return its result' do
|
129
|
+
expect(override_proc).to receive(:call).
|
130
|
+
with(test_fd_type, test_data_type, test_fd_type).
|
131
|
+
and_return(overriden_type)
|
132
|
+
|
133
|
+
is_expected.to eq overriden_type
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '.get_width_values(information_schema_columns, type_hash)' do
|
140
|
+
subject { described_class.send(:get_width_values,
|
141
|
+
information_schema_columns, type_hash) }
|
142
|
+
|
143
|
+
let(:type_hash) { {} }
|
144
|
+
|
145
|
+
context 'with no width attr' do
|
146
|
+
before do
|
147
|
+
type_hash.delete(:width_attrs)
|
148
|
+
end
|
149
|
+
context 'without default' do
|
150
|
+
before do
|
151
|
+
type_hash.delete(:def_width)
|
152
|
+
end
|
153
|
+
|
154
|
+
it { is_expected.to be_nil }
|
155
|
+
end
|
156
|
+
context 'with default' do
|
157
|
+
before do
|
158
|
+
type_hash[:def_width] = [10]
|
159
|
+
end
|
160
|
+
|
161
|
+
it { expect{ subject }.to raise_error }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
context 'with a single width attr' do
|
165
|
+
before do
|
166
|
+
type_hash[:width_attrs] = ["char_octet_length"]
|
167
|
+
end
|
168
|
+
context 'without default' do
|
169
|
+
before do
|
170
|
+
type_hash.delete(:def_width)
|
171
|
+
end
|
172
|
+
context 'when attr value exists' do
|
173
|
+
before do
|
174
|
+
information_schema_columns["char_octet_length"] = 1024
|
175
|
+
end
|
176
|
+
|
177
|
+
it { is_expected.to eq [ 1024 ] }
|
178
|
+
end
|
179
|
+
context 'when attr value does not exist' do
|
180
|
+
before do
|
181
|
+
information_schema_columns.delete("char_octet_length")
|
182
|
+
end
|
183
|
+
|
184
|
+
it { is_expected.to be_nil }
|
185
|
+
end
|
186
|
+
end
|
187
|
+
context 'with default' do
|
188
|
+
before do
|
189
|
+
type_hash[:def_width] = [10]
|
190
|
+
end
|
191
|
+
context 'when attr value exists' do
|
192
|
+
before do
|
193
|
+
information_schema_columns["char_octet_length"] = 1024
|
194
|
+
end
|
195
|
+
|
196
|
+
it { is_expected.to eq [1024] }
|
197
|
+
end
|
198
|
+
context 'when attr value does not exist' do
|
199
|
+
before do
|
200
|
+
information_schema_columns.delete("char_octet_length")
|
201
|
+
end
|
202
|
+
|
203
|
+
it { is_expected.to eq [10] }
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
context 'with two width attrs' do
|
208
|
+
before do
|
209
|
+
type_hash[:width_attrs] = ["precision", "scale"]
|
210
|
+
end
|
211
|
+
context 'without default' do
|
212
|
+
before do
|
213
|
+
type_hash.delete(:def_width)
|
214
|
+
end
|
215
|
+
context 'when the 1st attr value exists' do
|
216
|
+
before do
|
217
|
+
information_schema_columns["precision"] = 23
|
218
|
+
end
|
219
|
+
context 'when the 2nd attr value exists' do
|
220
|
+
before do
|
221
|
+
information_schema_columns["scale"] = 2
|
222
|
+
end
|
223
|
+
|
224
|
+
it { is_expected.to eq [23, 2] }
|
225
|
+
end
|
226
|
+
context 'when the 2nd attr value does not exist' do
|
227
|
+
before do
|
228
|
+
information_schema_columns.delete("scale")
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'omits trailing nils' do
|
232
|
+
is_expected.to eq [23]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
context 'when the 1st attr value does not exist' do
|
237
|
+
before do
|
238
|
+
information_schema_columns.delete("precision")
|
239
|
+
end
|
240
|
+
context 'when the 2nd attr value exists' do
|
241
|
+
before do
|
242
|
+
information_schema_columns["scale"] = 2
|
243
|
+
end
|
244
|
+
|
245
|
+
it { expect{subject}.to raise_error }
|
246
|
+
end
|
247
|
+
context 'when the 2nd attr value does not exist' do
|
248
|
+
before do
|
249
|
+
information_schema_columns.delete("scale")
|
250
|
+
end
|
251
|
+
|
252
|
+
it { is_expected.to be_nil }
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
context 'with default' do
|
257
|
+
before do
|
258
|
+
type_hash[:def_width] = [10, 0]
|
259
|
+
end
|
260
|
+
context 'when the 1st attr value exists' do
|
261
|
+
before do
|
262
|
+
information_schema_columns["precision"] = 23
|
263
|
+
end
|
264
|
+
context 'when the 2nd attr value exists' do
|
265
|
+
before do
|
266
|
+
information_schema_columns["scale"] = 2
|
267
|
+
end
|
268
|
+
|
269
|
+
it { is_expected.to eq [23, 2] }
|
270
|
+
end
|
271
|
+
context 'when the 2nd attr value does not exist' do
|
272
|
+
before do
|
273
|
+
information_schema_columns.delete("scale")
|
274
|
+
end
|
275
|
+
|
276
|
+
it { is_expected.to eq [23, 0] }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
context 'when the 1st attr value does not exist' do
|
280
|
+
before do
|
281
|
+
information_schema_columns.delete("precision")
|
282
|
+
end
|
283
|
+
context 'when the 2nd attr value exists' do
|
284
|
+
before do
|
285
|
+
information_schema_columns["scale"] = 2
|
286
|
+
end
|
287
|
+
|
288
|
+
it { is_expected.to eq [10, 2] }
|
289
|
+
end
|
290
|
+
context 'when the 2nd attr value does not exist' do
|
291
|
+
before do
|
292
|
+
information_schema_columns.delete("scale")
|
293
|
+
end
|
294
|
+
|
295
|
+
it { is_expected.to eq [10, 0] }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
context 'when the number of default values does not match
|
300
|
+
the attr number' do
|
301
|
+
before do
|
302
|
+
type_hash[:def_width] = [10]
|
303
|
+
end
|
304
|
+
context 'when the 1st attr value exists' do
|
305
|
+
before do
|
306
|
+
information_schema_columns["precision"] = 23
|
307
|
+
end
|
308
|
+
context 'when the 2nd attr value exists' do
|
309
|
+
before do
|
310
|
+
information_schema_columns["scale"] = 2
|
311
|
+
end
|
312
|
+
|
313
|
+
it { expect{subject}.to raise_error }
|
314
|
+
end
|
315
|
+
context 'when the 2nd attr value does not exist' do
|
316
|
+
before do
|
317
|
+
information_schema_columns.delete("scale")
|
318
|
+
end
|
319
|
+
|
320
|
+
it { expect{subject}.to raise_error }
|
321
|
+
end
|
322
|
+
end
|
323
|
+
context 'when the 1st attr value does not exist' do
|
324
|
+
before do
|
325
|
+
information_schema_columns.delete("precision")
|
326
|
+
end
|
327
|
+
context 'when the 2nd attr value exists' do
|
328
|
+
before do
|
329
|
+
information_schema_columns["scale"] = 2
|
330
|
+
end
|
331
|
+
|
332
|
+
it { expect{subject}.to raise_error }
|
333
|
+
end
|
334
|
+
context 'when the 2nd attr value does not exist' do
|
335
|
+
before do
|
336
|
+
information_schema_columns.delete("scale")
|
337
|
+
end
|
338
|
+
|
339
|
+
it { expect{subject}.to raise_error }
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
end
|