flydata 0.3.9 → 0.3.10
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 +4 -4
- data/VERSION +1 -1
- data/flydata-core/lib/flydata-core/errors.rb +23 -3
- data/flydata-core/lib/flydata-core/fluent-plugins/multi_buffer.rb +8 -0
- data/flydata-core/lib/flydata-core/logger.rb +39 -7
- data/flydata-core/lib/flydata-core/table_def/mysql_table_def.rb +1 -0
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +31 -14
- data/flydata-core/spec/table_def/mysql_table_def_spec.rb +8 -1
- data/flydata-core/spec/table_def/mysql_to_redshift_table_def_spec.rb +27 -21
- data/flydata-core/spec/table_def/mysqldump_test_table_all.dump +3 -0
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +107 -6
- data/flydata.gemspec +5 -4
- data/lib/flydata/command/sync.rb +6 -3
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 478d29c0767a534808dea15674528d5b5442bbed
|
4
|
+
data.tar.gz: c6536fb66fedffbdcc52069cb28f32f74fe3465d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b97f3acc0e763fcff4f2d4a18dcc4d9625d736db229b00554aee36da0ff8e68a189324a46abb3d985dfd1e2d4964ec6963a9299d475170e759485cb1e07faec
|
7
|
+
data.tar.gz: fdee03e1c1bf32699f8c5157aa51f48ecf6f1c023d2160a63b996ca7ac0599fa952de02b55045715b4a66283083b204860201a31a157b9cbf92d2413aebc77d5
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.10
|
@@ -51,6 +51,7 @@ end
|
|
51
51
|
# RetryableError
|
52
52
|
|
53
53
|
class RetryableError < StandardError
|
54
|
+
NO_RETRY_LIMIT = :no_retry_limit
|
54
55
|
def initialize(original_exception, retry_alert_limit = nil)
|
55
56
|
@original_exception = original_exception
|
56
57
|
@retry_alert_limit = retry_alert_limit
|
@@ -59,10 +60,20 @@ class RetryableError < StandardError
|
|
59
60
|
attr_reader :retry_alert_limit
|
60
61
|
end
|
61
62
|
|
62
|
-
#
|
63
|
+
# UserMaintenanceError
|
64
|
+
|
65
|
+
class UserMaintenanceError < StandardError
|
66
|
+
end
|
67
|
+
|
68
|
+
# An error that indicates that sync record was received for a table whose sync is broken
|
69
|
+
# These records cannot be retried, should be ignored
|
70
|
+
class BrokenTableSyncError < StandardError
|
71
|
+
end
|
72
|
+
|
73
|
+
# FlyDataError
|
63
74
|
# data_node_id, data_entry_id, chunk_identifier, table_name, err_code, err_reason, err_level
|
64
75
|
|
65
|
-
class
|
76
|
+
class FlydataError < StandardError
|
66
77
|
def initialize(error_reason, error_content = {})
|
67
78
|
error_content = if error_reason.kind_of?(String)
|
68
79
|
{ err_reason: error_reason}.merge(error_content)
|
@@ -125,6 +136,14 @@ class DataDeliveryError < StandardError
|
|
125
136
|
end
|
126
137
|
end
|
127
138
|
|
139
|
+
# DataDeliveryError
|
140
|
+
# An error which results in data clog or loss of information.
|
141
|
+
# This type of error gets reported to customer as data delivery error.
|
142
|
+
# data_node_id, data_entry_id, chunk_identifier, table_name, err_code, err_reason, err_level
|
143
|
+
|
144
|
+
class DataDeliveryError < FlydataError
|
145
|
+
end
|
146
|
+
|
128
147
|
# + RecordDeliveryError
|
129
148
|
# data_node_id, data_entry_id, chunk_identifier, table_name, err_code, err_reason, err_level, record_no, raw_record
|
130
149
|
|
@@ -174,7 +193,8 @@ class TableRevisionError < RecordDeliveryError
|
|
174
193
|
end
|
175
194
|
|
176
195
|
# Table's revision is lower than the record's revision. Should catch up soon.
|
177
|
-
class StaleTableRevisionError <
|
196
|
+
class StaleTableRevisionError < FlydataError
|
197
|
+
def err_code; ErrorCode::TABLE_REVISION_ERROR; end
|
178
198
|
end
|
179
199
|
|
180
200
|
# Unsupported ALTER TABLE which breaks the tables sync consistency.
|
@@ -108,33 +108,63 @@ module FlydataCore
|
|
108
108
|
def log_common(level, message, log_params, options)
|
109
109
|
msg = build_log_message(level, message, log_params, options)
|
110
110
|
before_logging(level, message, msg, log_params, options)
|
111
|
-
get_logger(options)
|
111
|
+
logger = get_logger(options)
|
112
|
+
set_mutex(logger)
|
113
|
+
logger.mutex.synchronize do
|
114
|
+
original_depth_offset = nil
|
115
|
+
if logger.instance_variable_defined? :@depth_offset
|
116
|
+
original_depth_offset = logger.instance_variable_get(:@depth_offset)
|
117
|
+
depth_offset = 3 # log_common + synchronize + synchronized block
|
118
|
+
depth_offset += options[:depth_offset] if options.has_key?(:depth_offset)
|
119
|
+
logger.instance_variable_set(:@depth_offset, original_depth_offset + depth_offset)
|
120
|
+
end
|
121
|
+
logger.send(level, msg)
|
122
|
+
if original_depth_offset
|
123
|
+
logger.instance_variable_set(:@depth_offset, original_depth_offset)
|
124
|
+
end
|
125
|
+
end
|
112
126
|
end
|
113
127
|
|
114
128
|
def log_debug(message, log_params = {}, options = {})
|
115
|
-
|
129
|
+
opt = { depth_offset: 1}.merge(options)
|
130
|
+
log_common(:debug, message, log_params, opt)
|
116
131
|
end
|
117
132
|
|
118
133
|
def log_info(message, log_params = {}, options = {})
|
119
|
-
|
134
|
+
opt = { depth_offset: 1}.merge(options)
|
135
|
+
log_common(:info, message, log_params, opt)
|
120
136
|
end
|
121
137
|
|
122
138
|
def log_warn(message, log_params = {}, options = {})
|
123
|
-
|
139
|
+
opt = { depth_offset: 1}.merge(options)
|
140
|
+
log_common(:warn, message, log_params, opt)
|
124
141
|
end
|
125
142
|
|
126
143
|
def log_error(message, log_params = {}, options = {})
|
127
|
-
|
144
|
+
opt = { depth_offset: 1}.merge(options)
|
145
|
+
log_common(:error, message, log_params, opt)
|
128
146
|
end
|
129
147
|
|
130
148
|
def log_error_with_backtrace(message, log_params = {}, options = {})
|
131
|
-
|
149
|
+
opt = { depth_offset: 1}.merge(options)
|
150
|
+
log_common(:error, message, log_params, opt.merge(backtrace: true))
|
132
151
|
end
|
133
152
|
|
134
153
|
def get_logger(options = {})
|
135
154
|
options[:logger] || logger || log_context_logger || $log
|
136
155
|
end
|
137
156
|
|
157
|
+
# set mutex if logger doesn't have one
|
158
|
+
def set_mutex(logger)
|
159
|
+
return if logger.respond_to?(:mutex)
|
160
|
+
|
161
|
+
mtx = Mutex.new
|
162
|
+
logger.instance_variable_set(:@mutex, mtx)
|
163
|
+
class << logger
|
164
|
+
attr_reader :mutex
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
138
168
|
def build_log_message(level, raw_message, log_params = {}, options = {})
|
139
169
|
message = raw_message.dup
|
140
170
|
# check keys
|
@@ -209,7 +239,9 @@ module FlydataCore
|
|
209
239
|
exception = exception.original_exception unless exception.original_exception.nil?
|
210
240
|
end
|
211
241
|
|
212
|
-
unless is_retryable_error &&
|
242
|
+
unless is_retryable_error &&
|
243
|
+
(retry_alert_limit == FlydataCore::RetryableError::NO_RETRY_LIMIT ||
|
244
|
+
retry_count < retry_alert_limit)
|
213
245
|
if exception.kind_of?(FlydataCore::DataDeliveryError)
|
214
246
|
# Do not log a DataDeliveryError as ERROR. It's a user error which
|
215
247
|
# should not cause a system alert
|
@@ -62,6 +62,7 @@ class MysqlTableDef
|
|
62
62
|
'tinytext' => {type: 'text'},
|
63
63
|
'varbinary' => {type: 'varbinary', override: PROC_override_varbinary},
|
64
64
|
'varchar' => {type: 'varchar', override: PROC_override_varchar},
|
65
|
+
'year' => {type: 'year'},
|
65
66
|
}
|
66
67
|
|
67
68
|
def self.convert_to_flydata_type(type)
|
@@ -33,6 +33,7 @@ class RedshiftTableDef
|
|
33
33
|
'time' => {type: 'timestamp', default_value: '0000-01-01'},
|
34
34
|
'varbinary' => {type: 'varchar', use_params: true, max_size: 65535, default_value: ''},
|
35
35
|
'varchar' => {type: 'varchar', use_params: true, max_size: 65535, default_value: ''},
|
36
|
+
'year' => {type: 'date', default_value: '0001-01-01'},
|
36
37
|
}
|
37
38
|
def self.from_flydata_tabledef(flydata_tabledef, options = {})
|
38
39
|
options[:flydata_ctl_table] = true unless options.has_key?(:flydata_ctl_table)
|
@@ -56,7 +57,7 @@ class RedshiftTableDef
|
|
56
57
|
CREATE SCHEMA "%s";
|
57
58
|
EOS
|
58
59
|
CREATE_FLYDATA_CTL_TABLE_SQL = <<EOS
|
59
|
-
CREATE TABLE %s(
|
60
|
+
CREATE TABLE IF NOT EXISTS %s(
|
60
61
|
id integer NOT NULL IDENTITY(1,1),
|
61
62
|
table_name varchar(128) NOT NULL,
|
62
63
|
column_name varchar(128) NOT NULL,
|
@@ -86,7 +87,7 @@ EOS
|
|
86
87
|
end
|
87
88
|
|
88
89
|
CREATE_TABLE_SQL = <<EOS
|
89
|
-
DROP TABLE %s;
|
90
|
+
DROP TABLE IF EXISTS %s;
|
90
91
|
CREATE TABLE %s (
|
91
92
|
%s
|
92
93
|
)%s;
|
@@ -141,9 +142,10 @@ EOS
|
|
141
142
|
|
142
143
|
NULL_STR = "NULL"
|
143
144
|
|
144
|
-
def self.replace_default_value(
|
145
|
+
def self.replace_default_value(redshift_type, default_value)
|
145
146
|
return NULL_STR if default_value.nil?
|
146
|
-
|
147
|
+
|
148
|
+
case redshift_type
|
147
149
|
when 'timestamp'
|
148
150
|
if default_value.upcase == "CURRENT_TIMESTAMP"
|
149
151
|
'SYSDATE'
|
@@ -224,7 +226,7 @@ EOS
|
|
224
226
|
def self.check_and_replace_max(params, max_size_a)
|
225
227
|
final_params = []
|
226
228
|
params.split(",").each_with_index do |param, i|
|
227
|
-
final_params << (/\d+/.match(param) && max_size_a[i] && param.to_i > max_size_a[i].to_i ?
|
229
|
+
final_params << (/\d+/.match(param) && max_size_a[i] && param.to_i > max_size_a[i].to_i ?
|
228
230
|
max_size_a[i] : param)
|
229
231
|
end
|
230
232
|
final_params.join(",")
|
@@ -234,23 +236,24 @@ EOS
|
|
234
236
|
TIME_REGEXP = Regexp.new('^(?<sign>-)?(?<hour>\d{2,3}):(?<minute>[0-5][0-9]):(?<second>[0-5][0-9](\.\d+)?)$')
|
235
237
|
|
236
238
|
def self.parse_timestamp(value)
|
237
|
-
|
238
|
-
if
|
239
|
+
value_str = value.to_s
|
240
|
+
return nil if value_str.empty?
|
241
|
+
if value.kind_of?(Integer) or /^\d+$/ === value_str
|
239
242
|
# Unix epoch in UTC
|
240
|
-
t = DateTime.strptime(
|
241
|
-
elsif APACHE_TIMESTAMP_REGEXP.match(
|
243
|
+
t = DateTime.strptime(value_str, '%s')
|
244
|
+
elsif APACHE_TIMESTAMP_REGEXP.match(value_str)
|
242
245
|
# apache time format
|
243
246
|
t = DateTime.strptime(value, "[%d/%b/%Y:%H:%M:%S %Z]")
|
244
|
-
elsif time_match = TIME_REGEXP.match(
|
247
|
+
elsif time_match = TIME_REGEXP.match(value_str)
|
245
248
|
t = convert_time_into_timestamp(time_match)
|
246
249
|
else
|
247
|
-
t = DateTime.parse(
|
250
|
+
t = DateTime.parse(value_str)
|
248
251
|
end
|
249
252
|
t = t.new_offset(0) # Redshift Plug-in uses UTC
|
250
253
|
t.strftime('%Y-%m-%d %H:%M:%S.%6N')
|
251
254
|
rescue ArgumentError => ae
|
252
255
|
# '0000-00-00 00:00:00' is valid for mysql datetime column
|
253
|
-
if
|
256
|
+
if value_str.start_with?('0000-00-00 00:00:00')
|
254
257
|
return '0001-01-01 00:00:00.000000'
|
255
258
|
else
|
256
259
|
raise ae
|
@@ -268,15 +271,29 @@ EOS
|
|
268
271
|
end
|
269
272
|
|
270
273
|
def self.parse_date(value)
|
271
|
-
dt = Date.parse(value)
|
274
|
+
dt = Date.parse(convert_year_into_date(value))
|
272
275
|
dt.strftime('%Y-%m-%d')
|
273
276
|
rescue ArgumentError => ae
|
274
277
|
# '0000-00-00' is valid for mysql date column
|
275
278
|
return '0001-01-01' if value == '0000-00-00'
|
276
279
|
raise ae
|
277
280
|
end
|
281
|
+
|
282
|
+
def self.convert_year_into_date(value)
|
283
|
+
if value == '0' || value == '0000'
|
284
|
+
converted_value = '0001-01-01' # '0001-01-01' is the "base" date
|
285
|
+
else
|
286
|
+
case value
|
287
|
+
when /^\d{4}$/
|
288
|
+
converted_value = "#{value}-01-01"
|
289
|
+
when /^\d{2}$/
|
290
|
+
converted_value = "#{value.to_i >= 70 ? "19" : "20"}#{value}-01-01"
|
291
|
+
else
|
292
|
+
converted_value = value # Return the value as is
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
278
296
|
end
|
279
297
|
|
280
298
|
end
|
281
299
|
end
|
282
|
-
|
@@ -56,7 +56,10 @@ describe MysqlTableDef do
|
|
56
56
|
{:column=>"col_tinyint", :type=>"int1(4)", :default=>nil},
|
57
57
|
{:column=>"col_tinytext", :type=>"text"},
|
58
58
|
{:column=>"col_varbinary", :type=>"varbinary(512)", :default=>nil},
|
59
|
-
{:column=>"col_varchar", :type=>"varchar(372)", :default=>nil}
|
59
|
+
{:column=>"col_varchar", :type=>"varchar(372)", :default=>nil},
|
60
|
+
{:column=>"col_year", :type=>"year", :default=>nil},
|
61
|
+
{:column=>"col_year_4", :type=>"year(4)", :default=>nil},
|
62
|
+
{:column=>"col_year_2", :type=>"year(2)", :default=>nil},
|
60
63
|
]
|
61
64
|
)
|
62
65
|
end
|
@@ -329,6 +332,10 @@ describe MysqlTableDef do
|
|
329
332
|
let(:flydata_type) { 'text' }
|
330
333
|
it_behaves_like "converting the mysql data type to the expected flydata type"
|
331
334
|
end
|
335
|
+
context "year" do
|
336
|
+
let(:flydata_type) { 'year' }
|
337
|
+
it_behaves_like "converting the mysql data type to the expected flydata type"
|
338
|
+
end
|
332
339
|
end
|
333
340
|
end
|
334
341
|
end
|
@@ -27,7 +27,7 @@ module FlydataCore
|
|
27
27
|
|
28
28
|
it 'should return ddl' do
|
29
29
|
expect(subject).to eq( <<EOT.strip )
|
30
|
-
CREATE TABLE "flydata_ctl_columns"(
|
30
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
31
31
|
id integer NOT NULL IDENTITY(1,1),
|
32
32
|
table_name varchar(128) NOT NULL,
|
33
33
|
column_name varchar(128) NOT NULL,
|
@@ -36,7 +36,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
36
36
|
ordinal_position int NOT NULL,
|
37
37
|
PRIMARY KEY(id)
|
38
38
|
) DISTKEY(table_name) SORTKEY(table_name);
|
39
|
-
DROP TABLE "test_table_all";
|
39
|
+
DROP TABLE IF EXISTS "test_table_all";
|
40
40
|
CREATE TABLE "test_table_all" (
|
41
41
|
"id" int8 NOT NULL,
|
42
42
|
"col_binary" varchar(202) DEFAULT NULL,
|
@@ -65,6 +65,9 @@ CREATE TABLE "test_table_all" (
|
|
65
65
|
"col_tinytext" varchar(max),
|
66
66
|
"col_varbinary" varchar(512) DEFAULT NULL,
|
67
67
|
"col_varchar" varchar(372) DEFAULT NULL,
|
68
|
+
"col_year" date DEFAULT NULL,
|
69
|
+
"col_year_4" date DEFAULT NULL,
|
70
|
+
"col_year_2" date DEFAULT NULL,
|
68
71
|
PRIMARY KEY (id)
|
69
72
|
) DISTKEY(id) SORTKEY(id);
|
70
73
|
DELETE FROM "flydata_ctl_columns" WHERE table_name = 'test_table_all';
|
@@ -95,7 +98,10 @@ INSERT INTO "flydata_ctl_columns" (table_name, column_name, src_data_type, ordin
|
|
95
98
|
('test_table_all', 'col_tinyint', 'int1(4)', 24),
|
96
99
|
('test_table_all', 'col_tinytext', 'text', 25),
|
97
100
|
('test_table_all', 'col_varbinary', 'varbinary(512)', 26),
|
98
|
-
('test_table_all', 'col_varchar', 'varchar(372)', 27)
|
101
|
+
('test_table_all', 'col_varchar', 'varchar(372)', 27),
|
102
|
+
('test_table_all', 'col_year', 'year', 28),
|
103
|
+
('test_table_all', 'col_year_4', 'year(4)', 29),
|
104
|
+
('test_table_all', 'col_year_2', 'year(2)', 30);
|
99
105
|
EOT
|
100
106
|
end
|
101
107
|
end
|
@@ -105,7 +111,7 @@ EOT
|
|
105
111
|
|
106
112
|
it 'should return ddl' do
|
107
113
|
expect(subject).to eq( <<EOT.strip )
|
108
|
-
CREATE TABLE "flydata_ctl_columns"(
|
114
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
109
115
|
id integer NOT NULL IDENTITY(1,1),
|
110
116
|
table_name varchar(128) NOT NULL,
|
111
117
|
column_name varchar(128) NOT NULL,
|
@@ -114,7 +120,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
114
120
|
ordinal_position int NOT NULL,
|
115
121
|
PRIMARY KEY(id)
|
116
122
|
) DISTKEY(table_name) SORTKEY(table_name);
|
117
|
-
DROP TABLE "bit_test_def_1";
|
123
|
+
DROP TABLE IF EXISTS "bit_test_def_1";
|
118
124
|
CREATE TABLE "bit_test_def_1" (
|
119
125
|
"id" int4 NOT NULL,
|
120
126
|
"bit_value" bigint DEFAULT 1,
|
@@ -135,7 +141,7 @@ EOT
|
|
135
141
|
|
136
142
|
it 'should return ddl' do
|
137
143
|
expect(subject).to eq( <<EOT.strip )
|
138
|
-
CREATE TABLE "flydata_ctl_columns"(
|
144
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
139
145
|
id integer NOT NULL IDENTITY(1,1),
|
140
146
|
table_name varchar(128) NOT NULL,
|
141
147
|
column_name varchar(128) NOT NULL,
|
@@ -144,7 +150,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
144
150
|
ordinal_position int NOT NULL,
|
145
151
|
PRIMARY KEY(id)
|
146
152
|
) DISTKEY(table_name) SORTKEY(table_name);
|
147
|
-
DROP TABLE "product_order";
|
153
|
+
DROP TABLE IF EXISTS "product_order";
|
148
154
|
CREATE TABLE "product_order" (
|
149
155
|
"no" int4 NOT NULL,
|
150
156
|
"product_category" int4 NOT NULL,
|
@@ -167,7 +173,7 @@ EOT
|
|
167
173
|
|
168
174
|
it 'should return ddl' do
|
169
175
|
expect(subject).to eq( <<EOT.strip )
|
170
|
-
CREATE TABLE "flydata_ctl_columns"(
|
176
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
171
177
|
id integer NOT NULL IDENTITY(1,1),
|
172
178
|
table_name varchar(128) NOT NULL,
|
173
179
|
column_name varchar(128) NOT NULL,
|
@@ -176,7 +182,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
176
182
|
ordinal_position int NOT NULL,
|
177
183
|
PRIMARY KEY(id)
|
178
184
|
) DISTKEY(table_name) SORTKEY(table_name);
|
179
|
-
DROP TABLE "test_table_column_comment";
|
185
|
+
DROP TABLE IF EXISTS "test_table_column_comment";
|
180
186
|
CREATE TABLE "test_table_column_comment" (
|
181
187
|
"id" int4 NOT NULL DEFAULT '0',
|
182
188
|
"value" varchar(max),
|
@@ -197,7 +203,7 @@ EOT
|
|
197
203
|
|
198
204
|
it 'should return ddl' do
|
199
205
|
expect(subject).to eq( <<EOT.strip )
|
200
|
-
CREATE TABLE "flydata_ctl_columns"(
|
206
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
201
207
|
id integer NOT NULL IDENTITY(1,1),
|
202
208
|
table_name varchar(128) NOT NULL,
|
203
209
|
column_name varchar(128) NOT NULL,
|
@@ -206,7 +212,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
206
212
|
ordinal_position int NOT NULL,
|
207
213
|
PRIMARY KEY(id)
|
208
214
|
) DISTKEY(table_name) SORTKEY(table_name);
|
209
|
-
DROP TABLE "test_table_enum";
|
215
|
+
DROP TABLE IF EXISTS "test_table_enum";
|
210
216
|
CREATE TABLE "test_table_enum" (
|
211
217
|
"id" int4 NOT NULL,
|
212
218
|
"enum_1" varchar encode bytedict DEFAULT NULL,
|
@@ -229,7 +235,7 @@ EOT
|
|
229
235
|
|
230
236
|
it 'should return ddl' do
|
231
237
|
expect(subject).to eq( <<EOT.strip )
|
232
|
-
CREATE TABLE "flydata_ctl_columns"(
|
238
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
233
239
|
id integer NOT NULL IDENTITY(1,1),
|
234
240
|
table_name varchar(128) NOT NULL,
|
235
241
|
column_name varchar(128) NOT NULL,
|
@@ -238,7 +244,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
238
244
|
ordinal_position int NOT NULL,
|
239
245
|
PRIMARY KEY(id)
|
240
246
|
) DISTKEY(table_name) SORTKEY(table_name);
|
241
|
-
DROP TABLE "test_table_multi_pk";
|
247
|
+
DROP TABLE IF EXISTS "test_table_multi_pk";
|
242
248
|
CREATE TABLE "test_table_multi_pk" (
|
243
249
|
"id1" int4 NOT NULL DEFAULT '0',
|
244
250
|
"id2" int4 NOT NULL DEFAULT '0',
|
@@ -267,7 +273,7 @@ EOT
|
|
267
273
|
|
268
274
|
it 'should return ddl' do
|
269
275
|
expect(subject).to eq( <<EOT.strip )
|
270
|
-
CREATE TABLE "flydata_ctl_columns"(
|
276
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
271
277
|
id integer NOT NULL IDENTITY(1,1),
|
272
278
|
table_name varchar(128) NOT NULL,
|
273
279
|
column_name varchar(128) NOT NULL,
|
@@ -276,7 +282,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
276
282
|
ordinal_position int NOT NULL,
|
277
283
|
PRIMARY KEY(id)
|
278
284
|
) DISTKEY(table_name) SORTKEY(table_name);
|
279
|
-
DROP TABLE "sample1";
|
285
|
+
DROP TABLE IF EXISTS "sample1";
|
280
286
|
CREATE TABLE "sample1" (
|
281
287
|
"id" int4 NOT NULL,
|
282
288
|
"title" varchar(768) DEFAULT NULL,
|
@@ -299,7 +305,7 @@ EOT
|
|
299
305
|
|
300
306
|
it 'should return ddl' do
|
301
307
|
expect(subject).to eq( <<EOT.strip )
|
302
|
-
CREATE TABLE "flydata_ctl_columns"(
|
308
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
303
309
|
id integer NOT NULL IDENTITY(1,1),
|
304
310
|
table_name varchar(128) NOT NULL,
|
305
311
|
column_name varchar(128) NOT NULL,
|
@@ -308,7 +314,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
308
314
|
ordinal_position int NOT NULL,
|
309
315
|
PRIMARY KEY(id)
|
310
316
|
) DISTKEY(table_name) SORTKEY(table_name);
|
311
|
-
DROP TABLE "sample1";
|
317
|
+
DROP TABLE IF EXISTS "sample1";
|
312
318
|
CREATE TABLE "sample1" (
|
313
319
|
"id" int4 NOT NULL,
|
314
320
|
"title" varchar(768) DEFAULT NULL,
|
@@ -331,7 +337,7 @@ EOT
|
|
331
337
|
|
332
338
|
it 'should return ddl' do
|
333
339
|
expect(subject).to eq( <<EOT.strip )
|
334
|
-
CREATE TABLE "flydata_ctl_columns"(
|
340
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
335
341
|
id integer NOT NULL IDENTITY(1,1),
|
336
342
|
table_name varchar(128) NOT NULL,
|
337
343
|
column_name varchar(128) NOT NULL,
|
@@ -340,7 +346,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
340
346
|
ordinal_position int NOT NULL,
|
341
347
|
PRIMARY KEY(id)
|
342
348
|
) DISTKEY(table_name) SORTKEY(table_name);
|
343
|
-
DROP TABLE "invoice_items";
|
349
|
+
DROP TABLE IF EXISTS "invoice_items";
|
344
350
|
CREATE TABLE "invoice_items" (
|
345
351
|
"id" int4 NOT NULL,
|
346
352
|
"app_id" int4 NOT NULL,
|
@@ -391,7 +397,7 @@ EOT
|
|
391
397
|
|
392
398
|
it 'should return ddl' do
|
393
399
|
expect(subject).to eq( <<EOT.strip )
|
394
|
-
CREATE TABLE "flydata_ctl_columns"(
|
400
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
395
401
|
id integer NOT NULL IDENTITY(1,1),
|
396
402
|
table_name varchar(128) NOT NULL,
|
397
403
|
column_name varchar(128) NOT NULL,
|
@@ -400,7 +406,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
400
406
|
ordinal_position int NOT NULL,
|
401
407
|
PRIMARY KEY(id)
|
402
408
|
) DISTKEY(table_name) SORTKEY(table_name);
|
403
|
-
DROP TABLE "zerofill_table";
|
409
|
+
DROP TABLE IF EXISTS "zerofill_table";
|
404
410
|
CREATE TABLE "zerofill_table" (
|
405
411
|
"id" int4 NOT NULL,
|
406
412
|
"value_int" int8 DEFAULT NULL,
|
@@ -50,6 +50,9 @@ CREATE TABLE `test_table_all` (
|
|
50
50
|
`col_tinytext` tinytext,
|
51
51
|
`col_varbinary` varbinary(255) DEFAULT NULL,
|
52
52
|
`col_varchar` varchar(124) DEFAULT NULL,
|
53
|
+
`col_year` year DEFAULT NULL,
|
54
|
+
`col_year_4` year(4) DEFAULT NULL,
|
55
|
+
`col_year_2` year(2) DEFAULT NULL,
|
53
56
|
PRIMARY KEY (`id`)
|
54
57
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='test table includes all kind of format type';
|
55
58
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
@@ -22,7 +22,7 @@ describe RedshiftTableDef do
|
|
22
22
|
context 'with simple flydatadef' do
|
23
23
|
it 'should return ddl' do
|
24
24
|
expect(subject).to eq( <<EOT.strip )
|
25
|
-
DROP TABLE "test_table";
|
25
|
+
DROP TABLE IF EXISTS "test_table";
|
26
26
|
CREATE TABLE "test_table" (
|
27
27
|
"id" int4 NOT NULL,
|
28
28
|
"age" int8,
|
@@ -43,7 +43,7 @@ EOT
|
|
43
43
|
|
44
44
|
it 'should return ddl including flydata_ctl_columns creation' do
|
45
45
|
expect(subject).to eq( <<EOT.strip )
|
46
|
-
CREATE TABLE "flydata_ctl_columns"(
|
46
|
+
CREATE TABLE IF NOT EXISTS "flydata_ctl_columns"(
|
47
47
|
id integer NOT NULL IDENTITY(1,1),
|
48
48
|
table_name varchar(128) NOT NULL,
|
49
49
|
column_name varchar(128) NOT NULL,
|
@@ -52,7 +52,7 @@ CREATE TABLE "flydata_ctl_columns"(
|
|
52
52
|
ordinal_position int NOT NULL,
|
53
53
|
PRIMARY KEY(id)
|
54
54
|
) DISTKEY(table_name) SORTKEY(table_name);
|
55
|
-
DROP TABLE "test_table";
|
55
|
+
DROP TABLE IF EXISTS "test_table";
|
56
56
|
CREATE TABLE "test_table" (
|
57
57
|
"id" int4 NOT NULL,
|
58
58
|
"age" int8,
|
@@ -80,7 +80,7 @@ EOT
|
|
80
80
|
|
81
81
|
it 'should add comment creation ddl' do
|
82
82
|
expect(subject).to eq( <<EOT.strip )
|
83
|
-
DROP TABLE "test_table";
|
83
|
+
DROP TABLE IF EXISTS "test_table";
|
84
84
|
CREATE TABLE "test_table" (
|
85
85
|
"id" int4 NOT NULL,
|
86
86
|
"value" varchar(max),
|
@@ -112,7 +112,7 @@ EOT
|
|
112
112
|
it 'should preappend schema name to table name' do
|
113
113
|
expect(subject).to eq( <<EOT.strip )
|
114
114
|
CREATE SCHEMA "test_schema";
|
115
|
-
CREATE TABLE "test_schema"."flydata_ctl_columns"(
|
115
|
+
CREATE TABLE IF NOT EXISTS "test_schema"."flydata_ctl_columns"(
|
116
116
|
id integer NOT NULL IDENTITY(1,1),
|
117
117
|
table_name varchar(128) NOT NULL,
|
118
118
|
column_name varchar(128) NOT NULL,
|
@@ -121,7 +121,7 @@ CREATE TABLE "test_schema"."flydata_ctl_columns"(
|
|
121
121
|
ordinal_position int NOT NULL,
|
122
122
|
PRIMARY KEY(id)
|
123
123
|
) DISTKEY(table_name) SORTKEY(table_name);
|
124
|
-
DROP TABLE "test_schema"."test_table";
|
124
|
+
DROP TABLE IF EXISTS "test_schema"."test_table";
|
125
125
|
CREATE TABLE "test_schema"."test_table" (
|
126
126
|
"id" int4 NOT NULL,
|
127
127
|
"value" varchar(max),
|
@@ -409,6 +409,50 @@ EOT
|
|
409
409
|
it_behaves_like *examples
|
410
410
|
end
|
411
411
|
end
|
412
|
+
|
413
|
+
context 'with year column def' do
|
414
|
+
before do
|
415
|
+
column[:column] = "value_year"
|
416
|
+
column[:type] = "year(4)"
|
417
|
+
end
|
418
|
+
let(:type_sql) { %Q|"value_year" date| }
|
419
|
+
let(:not_null_default_sql) { " DEFAULT '0001-01-01'" }
|
420
|
+
|
421
|
+
context 'when default_value is normal' do
|
422
|
+
let(:default_value) { "'2014'" }
|
423
|
+
let(:default_value_sql) { "'2014-01-01'" }
|
424
|
+
it_behaves_like *examples
|
425
|
+
end
|
426
|
+
|
427
|
+
context 'when default_value is 69' do
|
428
|
+
let(:default_value) { "'69'" }
|
429
|
+
let(:default_value_sql) { "'2069-01-01'" }
|
430
|
+
it_behaves_like *examples
|
431
|
+
end
|
432
|
+
|
433
|
+
context 'when default_value is 70' do
|
434
|
+
let(:default_value) { "'70'" }
|
435
|
+
let(:default_value_sql) { "'1970-01-01'" }
|
436
|
+
it_behaves_like *examples
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'when default_value is 0' do
|
440
|
+
let(:default_value) { "'0'" }
|
441
|
+
let(:default_value_sql) { "'0001-01-01'" }
|
442
|
+
it_behaves_like *examples
|
443
|
+
end
|
444
|
+
|
445
|
+
context 'when the type has no width' do
|
446
|
+
before do
|
447
|
+
column[:type] = "year"
|
448
|
+
end
|
449
|
+
context 'when default_value is normal' do
|
450
|
+
let(:default_value) { "'2014'" }
|
451
|
+
let(:default_value_sql) { "'2014-01-01'" }
|
452
|
+
it_behaves_like *examples
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
412
456
|
end
|
413
457
|
|
414
458
|
context 'for create table' do
|
@@ -592,6 +636,63 @@ EOT
|
|
592
636
|
let(:value) { 'abcd' }
|
593
637
|
it { expect{subject}.to raise_error(ArgumentError) }
|
594
638
|
end
|
639
|
+
|
640
|
+
context 'with boolean value' do
|
641
|
+
let(:value){ false }
|
642
|
+
it { expect{subject}.to raise_error(ArgumentError) }
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
describe '.convert_year_into_date' do
|
647
|
+
let(:value) { nil }
|
648
|
+
subject { described_class.convert_year_into_date(value) }
|
649
|
+
|
650
|
+
context 'with year values' do
|
651
|
+
context 'with value 0' do
|
652
|
+
let(:value){ '0' }
|
653
|
+
it { is_expected.to eq('0001-01-01') }
|
654
|
+
end
|
655
|
+
|
656
|
+
context 'with value 0000' do
|
657
|
+
let(:value){ '0000' }
|
658
|
+
it { is_expected.to eq('0001-01-01') }
|
659
|
+
end
|
660
|
+
|
661
|
+
context 'with year(4) >= 1970' do
|
662
|
+
let(:value){ '2000' }
|
663
|
+
it { is_expected.to eq('2000-01-01') }
|
664
|
+
end
|
665
|
+
|
666
|
+
context 'with year(4) < 1970' do
|
667
|
+
let(:value){ '1969' }
|
668
|
+
it { is_expected.to eq('1969-01-01') }
|
669
|
+
end
|
670
|
+
|
671
|
+
context 'with year(2) >= 70' do
|
672
|
+
let(:value){ '07' }
|
673
|
+
it { is_expected.to eq('2007-01-01') }
|
674
|
+
end
|
675
|
+
|
676
|
+
context 'with year(2) < 70' do
|
677
|
+
let(:value){ '69' }
|
678
|
+
it { is_expected.to eq('2069-01-01') }
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
context 'with date values' do
|
683
|
+
shared_examples "returning the input value as is" do
|
684
|
+
it { is_expected.to eq(value) }
|
685
|
+
end
|
686
|
+
context 'with valid date' do
|
687
|
+
let(:value){ '1920-01-01' }
|
688
|
+
it_behaves_like "returning the input value as is"
|
689
|
+
end
|
690
|
+
|
691
|
+
context 'with zero date' do
|
692
|
+
let(:value){ '0000-00-00' }
|
693
|
+
it_behaves_like "returning the input value as is"
|
694
|
+
end
|
695
|
+
end
|
595
696
|
end
|
596
697
|
end
|
597
698
|
|
data/flydata.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: flydata 0.3.
|
5
|
+
# stub: flydata 0.3.10 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "flydata"
|
9
|
-
s.version = "0.3.
|
9
|
+
s.version = "0.3.10"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Koichi Fujikawa", "Masashi Miyazaki", "Matthew Luu", "Mak Inada", "Sriram NS"]
|
14
|
-
s.date = "2015-03-
|
14
|
+
s.date = "2015-03-31"
|
15
15
|
s.description = "FlyData Agent"
|
16
16
|
s.email = "sysadmin@flydata.com"
|
17
17
|
s.executables = ["fdmysqldump", "flydata", "serverinfo"]
|
@@ -44,6 +44,7 @@ Gem::Specification.new do |s|
|
|
44
44
|
"flydata-core/lib/flydata-core/core_ext/object.rb",
|
45
45
|
"flydata-core/lib/flydata-core/core_ext/object/prepend.rb",
|
46
46
|
"flydata-core/lib/flydata-core/errors.rb",
|
47
|
+
"flydata-core/lib/flydata-core/fluent-plugins/multi_buffer.rb",
|
47
48
|
"flydata-core/lib/flydata-core/logger.rb",
|
48
49
|
"flydata-core/lib/flydata-core/table_def.rb",
|
49
50
|
"flydata-core/lib/flydata-core/table_def/mysql_table_def.rb",
|
@@ -167,7 +168,7 @@ Gem::Specification.new do |s|
|
|
167
168
|
]
|
168
169
|
s.homepage = "http://flydata.com/"
|
169
170
|
s.licenses = ["All right reserved."]
|
170
|
-
s.rubygems_version = "2.
|
171
|
+
s.rubygems_version = "2.4.3"
|
171
172
|
s.summary = "FlyData Agent"
|
172
173
|
|
173
174
|
if s.respond_to? :specification_version then
|
data/lib/flydata/command/sync.rb
CHANGED
@@ -24,7 +24,7 @@ module Flydata
|
|
24
24
|
class Sync < Base
|
25
25
|
include Helpers
|
26
26
|
INSERT_PROGRESS_INTERVAL = 1000
|
27
|
-
SERVER_DATA_PROCESSING_TIMEOUT =
|
27
|
+
SERVER_DATA_PROCESSING_TIMEOUT = 3600 # seconds
|
28
28
|
|
29
29
|
# for dump.pos file
|
30
30
|
STATUS_PARSING = 'PARSING'
|
@@ -179,7 +179,10 @@ EOS
|
|
179
179
|
sync_fm.table_rev_file_paths(*@input_tables),
|
180
180
|
sync_fm.table_ddl_file_paths(*@input_tables)
|
181
181
|
]
|
182
|
-
|
182
|
+
new_tables_after_reset = @new_tables + @input_tables
|
183
|
+
if @input_tables.empty? or @full_tables.empty? or @full_tables.all?{|ft| new_tables_after_reset.include?(ft)}
|
184
|
+
delete_files << sync_fm.binlog_path
|
185
|
+
end
|
183
186
|
delete_files.flatten.each do |path|
|
184
187
|
FileUtils.rm(path) if File.exists?(path)
|
185
188
|
end
|
@@ -737,13 +740,13 @@ Thank you for using FlyData!
|
|
737
740
|
def flush_buffer_and_stop(tables = [])
|
738
741
|
sender = Flydata::Command::Sender.new
|
739
742
|
sender.flush_client_buffer
|
743
|
+
sender.stop(quiet: true)
|
740
744
|
if opts.skip_flush?
|
741
745
|
log_info_stdout("Skip waiting for server data processing.")
|
742
746
|
else
|
743
747
|
wait_for_server_data_processing(
|
744
748
|
timeout: SERVER_DATA_PROCESSING_TIMEOUT, tables: tables)
|
745
749
|
end
|
746
|
-
sender.stop(quiet: true)
|
747
750
|
end
|
748
751
|
|
749
752
|
# Utility methods
|
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.3.
|
4
|
+
version: 0.3.10
|
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-03-
|
15
|
+
date: 2015-03-31 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rest-client
|
@@ -467,6 +467,7 @@ files:
|
|
467
467
|
- flydata-core/lib/flydata-core/core_ext/object.rb
|
468
468
|
- flydata-core/lib/flydata-core/core_ext/object/prepend.rb
|
469
469
|
- flydata-core/lib/flydata-core/errors.rb
|
470
|
+
- flydata-core/lib/flydata-core/fluent-plugins/multi_buffer.rb
|
470
471
|
- flydata-core/lib/flydata-core/logger.rb
|
471
472
|
- flydata-core/lib/flydata-core/table_def.rb
|
472
473
|
- flydata-core/lib/flydata-core/table_def/mysql_table_def.rb
|
@@ -607,7 +608,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
607
608
|
version: '0'
|
608
609
|
requirements: []
|
609
610
|
rubyforge_project:
|
610
|
-
rubygems_version: 2.
|
611
|
+
rubygems_version: 2.4.3
|
611
612
|
signing_key:
|
612
613
|
specification_version: 4
|
613
614
|
summary: FlyData Agent
|