flydata 0.1.12 → 0.1.13
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 +7 -0
- data/Gemfile +17 -18
- data/Gemfile.lock +68 -71
- data/VERSION +1 -1
- data/flydata.gemspec +58 -59
- data/lib/flydata/command/sync.rb +3 -1
- data/lib/flydata/fluent-plugins/mysql/alter_table_query_handler.rb +12 -13
- data/lib/flydata/fluent-plugins/mysql/binlog_query_dispatcher.rb +2 -1
- data/lib/flydata/fluent-plugins/mysql/binlog_record_handler.rb +7 -3
- data/lib/flydata/fluent-plugins/mysql/ddl_query_handler.rb +22 -0
- data/lib/flydata/parser/mysql/mysql_alter_table.treetop +27 -2
- data/lib/flydata/table_def/redshift_table_def.rb +30 -16
- data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +8 -9
- data/spec/flydata/parser/mysql/alter_table_parser_spec.rb +54 -0
- data/spec/flydata/table_def/redshift_table_def_spec.rb +130 -0
- metadata +161 -117
@@ -31,17 +31,19 @@ class RedshiftTableDef
|
|
31
31
|
}
|
32
32
|
def self.from_flydata_tabledef(flydata_tabledef, options = {})
|
33
33
|
options[:flydata_ctl_table] = true unless options.has_key?(:flydata_ctl_table)
|
34
|
+
schema_name = options[:schema_name]
|
34
35
|
|
35
36
|
tabledef = ""
|
36
|
-
tabledef += create_flydata_ctl_table_sql if options[:flydata_ctl_table]
|
37
|
-
tabledef += create_table_sql(flydata_tabledef)
|
38
|
-
tabledef += comment_sql(flydata_tabledef)
|
39
|
-
tabledef += flydata_ctl_sql(flydata_tabledef)
|
37
|
+
tabledef += create_flydata_ctl_table_sql(schema_name) if options[:flydata_ctl_table]
|
38
|
+
tabledef += create_table_sql(flydata_tabledef, schema_name)
|
39
|
+
tabledef += comment_sql(flydata_tabledef, schema_name)
|
40
|
+
tabledef += flydata_ctl_sql(flydata_tabledef, schema_name)
|
40
41
|
end
|
41
42
|
|
43
|
+
FLYDATA_CTL_COLUMNS_TABLE = "flydata_ctl_columns"
|
42
44
|
CREATE_FLYDATA_CTL_TABLE_SQL = <<EOS
|
43
|
-
DROP TABLE
|
44
|
-
CREATE TABLE
|
45
|
+
DROP TABLE %s;
|
46
|
+
CREATE TABLE %s(
|
45
47
|
id integer NOT NULL IDENTITY(1,1),
|
46
48
|
table_name varchar(128) NOT NULL,
|
47
49
|
column_name varchar(128) NOT NULL,
|
@@ -51,9 +53,19 @@ CREATE TABLE flydata_ctl_columns (
|
|
51
53
|
PRIMARY KEY(id)
|
52
54
|
) DISTKEY(table_name) SORTKEY(table_name);
|
53
55
|
EOS
|
54
|
-
|
56
|
+
|
57
|
+
def self.table_name_for_ddl(table_name, schema_name)
|
58
|
+
schema_name.to_s.empty? ? "\"#{table_name}\"" : "\"#{schema_name}\".\"#{table_name}\""
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.flydata_ctl_table_for_ddl(schema_name)
|
62
|
+
table_name_for_ddl(FLYDATA_CTL_COLUMNS_TABLE, schema_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.create_flydata_ctl_table_sql(schema_name)
|
55
66
|
# No drop table here intentionally because losing the data is fatal.
|
56
|
-
|
67
|
+
tbl = flydata_ctl_table_for_ddl(schema_name)
|
68
|
+
CREATE_FLYDATA_CTL_TABLE_SQL % [tbl, tbl]
|
57
69
|
end
|
58
70
|
|
59
71
|
CREATE_TABLE_SQL = <<EOS
|
@@ -63,7 +75,7 @@ CREATE TABLE %s (
|
|
63
75
|
);
|
64
76
|
EOS
|
65
77
|
|
66
|
-
def self.create_table_sql(flydata_tabledef)
|
78
|
+
def self.create_table_sql(flydata_tabledef, schema_name)
|
67
79
|
lines = flydata_tabledef[:columns].collect{|column| column_def_sql(column) }
|
68
80
|
pk_def = primary_key_sql(flydata_tabledef)
|
69
81
|
lines << pk_def if pk_def
|
@@ -71,7 +83,8 @@ EOS
|
|
71
83
|
contents = lines.join(",\n")
|
72
84
|
|
73
85
|
table_name = flydata_tabledef[:table_name]
|
74
|
-
|
86
|
+
redshift_tbl = table_name_for_ddl(table_name, schema_name)
|
87
|
+
CREATE_TABLE_SQL % [redshift_tbl, redshift_tbl, contents]
|
75
88
|
end
|
76
89
|
|
77
90
|
def self.column_def_sql(column)
|
@@ -118,13 +131,13 @@ EOS
|
|
118
131
|
pks.empty? ? nil : " PRIMARY KEY (#{pks.join(',')})"
|
119
132
|
end
|
120
133
|
|
121
|
-
def self.comment_sql(flydata_tabledef)
|
134
|
+
def self.comment_sql(flydata_tabledef, schema_name)
|
122
135
|
sql = ""
|
123
136
|
flydata_tabledef[:columns].each do |col|
|
124
137
|
next unless col[:comment]
|
125
138
|
|
126
139
|
sql += <<EOS
|
127
|
-
COMMENT ON COLUMN #{flydata_tabledef[:table_name]}."#{col[:name]}"
|
140
|
+
COMMENT ON COLUMN #{table_name_for_ddl(flydata_tabledef[:table_name], schema_name)}."#{col[:name]}"
|
128
141
|
IS '#{col[:comment]}';
|
129
142
|
EOS
|
130
143
|
end
|
@@ -132,11 +145,12 @@ EOS
|
|
132
145
|
end
|
133
146
|
|
134
147
|
FLYDATA_CTL_COLUMNS_SQL = <<EOS
|
135
|
-
DELETE FROM
|
136
|
-
INSERT INTO
|
148
|
+
DELETE FROM %s WHERE table_name = '%s';
|
149
|
+
INSERT INTO %s (table_name, column_name, src_data_type, ordinal_position) VALUES
|
137
150
|
EOS
|
138
|
-
def self.flydata_ctl_sql(flydata_tabledef)
|
139
|
-
|
151
|
+
def self.flydata_ctl_sql(flydata_tabledef, schema_name)
|
152
|
+
flydata_ctl_tbl = flydata_ctl_table_for_ddl(schema_name)
|
153
|
+
sql = FLYDATA_CTL_COLUMNS_SQL % [ flydata_ctl_tbl, flydata_tabledef[:table_name], flydata_ctl_tbl ]
|
140
154
|
values = []
|
141
155
|
flydata_tabledef[:columns].each.with_index(1) do |col, i|
|
142
156
|
values << "('#{flydata_tabledef[:table_name]}', '#{col[:name]}', '#{escape(col[:type])}', #{i})"
|
@@ -280,16 +280,11 @@ EOT
|
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
283
|
-
context 'when received alter table event' do
|
284
|
-
it do
|
285
|
-
expect_no_emitted_record(alter_table_add_column_event)
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
#TODO: Uncomment the following test and delete the above one after supporting alter table
|
290
283
|
context 'when received alter table add column event' do
|
291
284
|
it do
|
292
|
-
|
285
|
+
# TODO Replace the expectation when enabling alter table
|
286
|
+
expect_no_emitted_record(alter_table_add_column_event)
|
287
|
+
=begin
|
293
288
|
expect_emitted_records(alter_table_add_column_event, {
|
294
289
|
type: :alter_table,
|
295
290
|
table_name: "test_table",
|
@@ -300,12 +295,15 @@ EOT
|
|
300
295
|
actions: [{
|
301
296
|
action: :add_column, column: "sum", :type=>'int4'}],
|
302
297
|
})
|
298
|
+
=end
|
303
299
|
end
|
304
300
|
end
|
305
301
|
|
306
302
|
context 'when received alter table drop column event' do
|
307
303
|
it do
|
308
|
-
|
304
|
+
# TODO Replace the expectation when enabling alter table
|
305
|
+
expect_no_emitted_record(alter_table_drop_column_event)
|
306
|
+
=begin
|
309
307
|
expect_emitted_records(alter_table_drop_column_event, {
|
310
308
|
type: :alter_table,
|
311
309
|
table_name: "test_table",
|
@@ -316,6 +314,7 @@ EOT
|
|
316
314
|
actions: [{
|
317
315
|
action: :drop_column, column: "sum"}],
|
318
316
|
})
|
317
|
+
=end
|
319
318
|
end
|
320
319
|
end
|
321
320
|
|
@@ -234,6 +234,60 @@ describe 'MysqlAlterTableParser' do
|
|
234
234
|
end
|
235
235
|
end
|
236
236
|
|
237
|
+
context 'when table_name is wrapped with backquote' do
|
238
|
+
let(:query) { "alter table `test_table` drop value" }
|
239
|
+
it do
|
240
|
+
expect(subject).to eq(
|
241
|
+
type: :alter_table,
|
242
|
+
table_name: "test_table",
|
243
|
+
actions: [{
|
244
|
+
action: :drop_column,
|
245
|
+
column: "value"
|
246
|
+
}])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'when keywords are capitalized' do
|
251
|
+
let(:query) { "ALTER TABLE `test_table` DROP value" }
|
252
|
+
it do
|
253
|
+
expect(subject).to eq(
|
254
|
+
type: :alter_table,
|
255
|
+
table_name: "test_table",
|
256
|
+
actions: [{
|
257
|
+
action: :drop_column,
|
258
|
+
column: "value"
|
259
|
+
}])
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
context 'when table_name includes schema' do
|
264
|
+
let(:query) { "alter table test_schema.test_table drop value" }
|
265
|
+
it do
|
266
|
+
expect(subject).to eq(
|
267
|
+
type: :alter_table,
|
268
|
+
schema_name: "test_schema",
|
269
|
+
table_name: "test_table",
|
270
|
+
actions: [{
|
271
|
+
action: :drop_column,
|
272
|
+
column: "value"
|
273
|
+
}])
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'when table_name includes schema with quotes' do
|
278
|
+
let(:query) { "alter table `test_schema`.`test_table` drop `value`" }
|
279
|
+
it do
|
280
|
+
expect(subject).to eq(
|
281
|
+
type: :alter_table,
|
282
|
+
schema_name: "test_schema",
|
283
|
+
table_name: "test_table",
|
284
|
+
actions: [{
|
285
|
+
action: :drop_column,
|
286
|
+
column: "value"
|
287
|
+
}])
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
237
291
|
context 'when query has unsupported drop dextension' do
|
238
292
|
subject { parser.parse(query) }
|
239
293
|
|
@@ -6,6 +6,136 @@ module TableDef
|
|
6
6
|
|
7
7
|
describe RedshiftTableDef do
|
8
8
|
|
9
|
+
describe '.from_flydata_tabledef' do
|
10
|
+
let(:flydata_tabledef) { {
|
11
|
+
table_name: "test_table",
|
12
|
+
columns: [
|
13
|
+
{ name: "id", type: "int4(11)", not_null: true, primary_key: true },
|
14
|
+
{ name: "value", type: "text" },
|
15
|
+
],
|
16
|
+
default_charset: "utf8;"} }
|
17
|
+
let(:option) { { flydata_ctl_table: false } }
|
18
|
+
|
19
|
+
subject { described_class.from_flydata_tabledef(flydata_tabledef, option) }
|
20
|
+
|
21
|
+
context 'with simple flydatadef' do
|
22
|
+
it 'should return ddl' do
|
23
|
+
expect(subject).to eq( <<EOT.strip )
|
24
|
+
DROP TABLE "test_table";
|
25
|
+
CREATE TABLE "test_table" (
|
26
|
+
"id" int4 NOT NULL,
|
27
|
+
"value" varchar(max),
|
28
|
+
PRIMARY KEY (id)
|
29
|
+
);
|
30
|
+
DELETE FROM "flydata_ctl_columns" WHERE table_name = 'test_table';
|
31
|
+
INSERT INTO "flydata_ctl_columns" (table_name, column_name, src_data_type, ordinal_position) VALUES
|
32
|
+
('test_table', 'id', 'int4(11)', 1),
|
33
|
+
('test_table', 'value', 'text', 2);
|
34
|
+
EOT
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with flydata_ctl_columns option true' do
|
39
|
+
let(:option) { { flydata_ctl_columns: true } }
|
40
|
+
|
41
|
+
it 'should return ddl including flydata_ctl_columns creation' do
|
42
|
+
expect(subject).to eq( <<EOT.strip )
|
43
|
+
DROP TABLE "flydata_ctl_columns";
|
44
|
+
CREATE TABLE "flydata_ctl_columns"(
|
45
|
+
id integer NOT NULL IDENTITY(1,1),
|
46
|
+
table_name varchar(128) NOT NULL,
|
47
|
+
column_name varchar(128) NOT NULL,
|
48
|
+
src_data_type varchar(1024) NOT NULL,
|
49
|
+
revision int NOT NULL DEFAULT 1,
|
50
|
+
ordinal_position int NOT NULL,
|
51
|
+
PRIMARY KEY(id)
|
52
|
+
) DISTKEY(table_name) SORTKEY(table_name);
|
53
|
+
DROP TABLE "test_table";
|
54
|
+
CREATE TABLE "test_table" (
|
55
|
+
"id" int4 NOT NULL,
|
56
|
+
"value" varchar(max),
|
57
|
+
PRIMARY KEY (id)
|
58
|
+
);
|
59
|
+
DELETE FROM "flydata_ctl_columns" WHERE table_name = 'test_table';
|
60
|
+
INSERT INTO "flydata_ctl_columns" (table_name, column_name, src_data_type, ordinal_position) VALUES
|
61
|
+
('test_table', 'id', 'int4(11)', 1),
|
62
|
+
('test_table', 'value', 'text', 2);
|
63
|
+
EOT
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with flydatadef with comment' do
|
68
|
+
let(:flydata_tabledef) { {
|
69
|
+
table_name: "test_table",
|
70
|
+
columns: [
|
71
|
+
{ name: "id", type: "int4(11)", not_null: true, primary_key: true },
|
72
|
+
{ name: "value", type: "text" },
|
73
|
+
{ name: "cmnt", type: "text", comment: "helloworld" },
|
74
|
+
],
|
75
|
+
default_charset: "utf8;"} }
|
76
|
+
|
77
|
+
it 'should add comment creation ddl' do
|
78
|
+
expect(subject).to eq( <<EOT.strip )
|
79
|
+
DROP TABLE "test_table";
|
80
|
+
CREATE TABLE "test_table" (
|
81
|
+
"id" int4 NOT NULL,
|
82
|
+
"value" varchar(max),
|
83
|
+
"cmnt" varchar(max),
|
84
|
+
PRIMARY KEY (id)
|
85
|
+
);
|
86
|
+
COMMENT ON COLUMN "test_table"."cmnt"
|
87
|
+
IS 'helloworld';
|
88
|
+
DELETE FROM "flydata_ctl_columns" WHERE table_name = 'test_table';
|
89
|
+
INSERT INTO "flydata_ctl_columns" (table_name, column_name, src_data_type, ordinal_position) VALUES
|
90
|
+
('test_table', 'id', 'int4(11)', 1),
|
91
|
+
('test_table', 'value', 'text', 2),
|
92
|
+
('test_table', 'cmnt', 'text', 3);
|
93
|
+
EOT
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'with schema_name' do
|
98
|
+
let(:flydata_tabledef) { {
|
99
|
+
table_name: "test_table",
|
100
|
+
columns: [
|
101
|
+
{ name: "id", type: "int4(11)", not_null: true, primary_key: true },
|
102
|
+
{ name: "value", type: "text" },
|
103
|
+
{ name: "cmnt", type: "text", comment: "helloworld" },
|
104
|
+
],
|
105
|
+
default_charset: "utf8;"} }
|
106
|
+
let(:option) { { flydata_ctl_table: true, schema_name: 'test_schema' } }
|
107
|
+
|
108
|
+
it 'should preappend schema name to table name' do
|
109
|
+
expect(subject).to eq( <<EOT.strip )
|
110
|
+
DROP TABLE "test_schema"."flydata_ctl_columns";
|
111
|
+
CREATE TABLE "test_schema"."flydata_ctl_columns"(
|
112
|
+
id integer NOT NULL IDENTITY(1,1),
|
113
|
+
table_name varchar(128) NOT NULL,
|
114
|
+
column_name varchar(128) NOT NULL,
|
115
|
+
src_data_type varchar(1024) NOT NULL,
|
116
|
+
revision int NOT NULL DEFAULT 1,
|
117
|
+
ordinal_position int NOT NULL,
|
118
|
+
PRIMARY KEY(id)
|
119
|
+
) DISTKEY(table_name) SORTKEY(table_name);
|
120
|
+
DROP TABLE "test_schema"."test_table";
|
121
|
+
CREATE TABLE "test_schema"."test_table" (
|
122
|
+
"id" int4 NOT NULL,
|
123
|
+
"value" varchar(max),
|
124
|
+
"cmnt" varchar(max),
|
125
|
+
PRIMARY KEY (id)
|
126
|
+
);
|
127
|
+
COMMENT ON COLUMN "test_schema"."test_table"."cmnt"
|
128
|
+
IS 'helloworld';
|
129
|
+
DELETE FROM "test_schema"."flydata_ctl_columns" WHERE table_name = 'test_table';
|
130
|
+
INSERT INTO "test_schema"."flydata_ctl_columns" (table_name, column_name, src_data_type, ordinal_position) VALUES
|
131
|
+
('test_table', 'id', 'int4(11)', 1),
|
132
|
+
('test_table', 'value', 'text', 2),
|
133
|
+
('test_table', 'cmnt', 'text', 3);
|
134
|
+
EOT
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
9
139
|
describe '.column_def_sql' do
|
10
140
|
let(:column) { {} }
|
11
141
|
subject { described_class.column_def_sql(column) }
|