flydata 0.1.12 → 0.1.13
Sign up to get free protection for your applications and to get access to all the features.
- 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) }
|