flydata 0.7.9 → 0.7.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/compatibility_check/base.rb +24 -0
- data/flydata-core/lib/flydata-core/compatibility_check/db_compatibility_checker.rb +131 -0
- data/flydata-core/lib/flydata-core/mysql/compatibility_checker.rb +46 -69
- data/flydata-core/lib/flydata-core/postgresql/compatibility_checker.rb +57 -66
- data/flydata-core/spec/mysql/compatibility_checker_spec.rb +85 -4
- data/flydata-core/spec/postgresql/compatibility_checker_spec.rb +124 -10
- data/flydata.gemspec +0 -0
- data/lib/flydata/source_mysql/plugin_support/binlog_record_handler.rb +4 -0
- data/lib/flydata/source_mysql/plugin_support/create_table_query_handler.rb +7 -2
- data/lib/flydata/source_mysql/plugin_support/drop_table_query_handler.rb +7 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dde125415d768ce91d31ba571250fcc82211a6c
|
4
|
+
data.tar.gz: 47de949761414acc3786397da03180e4f862cab8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f21358a59fb60e600a0a823a80574bd923b269093dc1d91618f9dc3e6ef7813ab385171666f62e8c86ad84a94e6db1d4c4dbad561acf9276b4ff4f94af12a32
|
7
|
+
data.tar.gz: 51daad9b9152816d384b367df2dbdffc3f3a0f3e9d07cf103759a8c2835d7b1bc71356961286f86da447a1dc0b2a218a9d9a669a6e4616f6da746ad8a4fb361d
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.10
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'flydata-core/errors'
|
2
|
+
|
3
|
+
module FlydataCore
|
4
|
+
module CompatibilityCheck
|
5
|
+
class Base
|
6
|
+
def initialize(option = {})
|
7
|
+
@option = option || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def do_check(option = @option, &block)
|
11
|
+
result = block.call create_query(option)
|
12
|
+
check_result(result, option)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Override
|
16
|
+
#def create_query(option = @option)
|
17
|
+
#end
|
18
|
+
|
19
|
+
# Override
|
20
|
+
#def validate_result(result, option = @option)
|
21
|
+
#end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'flydata-core/compatibility_check/base'
|
2
|
+
|
3
|
+
module FlydataCore
|
4
|
+
module CompatibilityCheck
|
5
|
+
class DbCompatibilityChecker < Base
|
6
|
+
def do_check(option = @option, &block)
|
7
|
+
query = create_query(option)
|
8
|
+
result = if block
|
9
|
+
block.call query
|
10
|
+
else
|
11
|
+
exec_query(query)
|
12
|
+
end
|
13
|
+
check_result(result, option)
|
14
|
+
end
|
15
|
+
|
16
|
+
def exec_query(query)
|
17
|
+
begin
|
18
|
+
client = build_db_client(@option)
|
19
|
+
client.query(query)
|
20
|
+
ensure
|
21
|
+
client.close rescue nil if client
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Override
|
26
|
+
#def build_db_client(option)
|
27
|
+
#end
|
28
|
+
|
29
|
+
# Utility for building query
|
30
|
+
# input: Array ['table_1', 'table_2', 'table_3', ...]
|
31
|
+
# output: String "'table_1','table_2'"
|
32
|
+
def table_names_in_query(tables)
|
33
|
+
tables.collect{|tn| "'#{tn}'"}.join(',')
|
34
|
+
end
|
35
|
+
|
36
|
+
def word_for_table_schema
|
37
|
+
"schema"
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_schema_and_tables(result)
|
41
|
+
table_schema = nil
|
42
|
+
tables = []
|
43
|
+
result.each do |r|
|
44
|
+
tbl = r['table_name']
|
45
|
+
tables << tbl unless tbl.to_s.empty?
|
46
|
+
table_schema = r['table_schema'] if table_schema.nil?
|
47
|
+
end
|
48
|
+
[table_schema, tables]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module TableExistenceCheck
|
53
|
+
# Override
|
54
|
+
# TABLE_EXISTENCE_CHECK_QUERY_TMPLT = SELECT...
|
55
|
+
# COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError
|
56
|
+
|
57
|
+
def create_query(option = @option)
|
58
|
+
self.class::TABLE_EXISTENCE_CHECK_QUERY_TMPLT % schema_and_table_in_query(option)
|
59
|
+
end
|
60
|
+
|
61
|
+
def check_result(result, option = @option)
|
62
|
+
table_schema, existing_tables = get_schema_and_tables(result)
|
63
|
+
missing_tables = option[:tables] - existing_tables
|
64
|
+
|
65
|
+
unless missing_tables.empty?
|
66
|
+
raise self.class::COMPATIBILITY_ERROR_CLASS,
|
67
|
+
"These tables are missing in \"#{table_schema}\" #{word_for_table_schema}. Create these tables on your database or remove them from the data entry: #{missing_tables.join(", ")}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module PrimaryKeyCheck
|
73
|
+
# Override
|
74
|
+
# PK_CHECK_QUERY_TMPLT = SELECT...
|
75
|
+
# COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError
|
76
|
+
|
77
|
+
def create_query(option = @option)
|
78
|
+
pk_override = option[:pk_override] || {}
|
79
|
+
tables = option[:tables].select{|tbl| pk_override[tbl.to_s].nil? } # exclude tables having pk_override
|
80
|
+
return nil if tables.empty?
|
81
|
+
(self.class::PK_CHECK_QUERY_TMPLT) % schema_and_table_in_query(option.merge(tables: tables))
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_result(result, option = @option)
|
85
|
+
table_schema, missing_pk_tables = get_schema_and_tables(result)
|
86
|
+
unless missing_pk_tables.empty?
|
87
|
+
raise self.class::COMPATIBILITY_ERROR_CLASS,
|
88
|
+
"Primary key is required for tables to sync. " +
|
89
|
+
"Add primary key or remove following tables in \"#{table_schema}\" #{word_for_table_schema} from data entry: #{missing_pk_tables.join(", ")}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module PkOverrideCheck
|
95
|
+
# Override
|
96
|
+
# PK_OVERRIDE_QUERY_TMPLT = SELECT...
|
97
|
+
# COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError
|
98
|
+
|
99
|
+
def create_query(option = @option)
|
100
|
+
pk_override = option[:pk_override] || {}
|
101
|
+
return nil if pk_override.empty?
|
102
|
+
self.class::PK_OVERRIDE_QUERY_TMPLT % schema_and_table_in_query(option.merge(tables: pk_override.keys))
|
103
|
+
end
|
104
|
+
|
105
|
+
def check_result(result, option = @option)
|
106
|
+
tbl_cols = Hash.new{|h, k| h[k] = []} # key: table-name, value: array of column-name
|
107
|
+
table_schema = nil
|
108
|
+
result.each do |r|
|
109
|
+
tbl_cols[r['table_name']] << r['column_name']
|
110
|
+
table_schema = r['table_schema'] if table_schema.nil?
|
111
|
+
end
|
112
|
+
|
113
|
+
pk_override = option[:pk_override] || {}
|
114
|
+
missing_pk_override = {}
|
115
|
+
pk_override.each do |tbl, pk_cols|
|
116
|
+
missing_cols = pk_cols - tbl_cols[tbl]
|
117
|
+
missing_pk_override[tbl] = missing_cols unless missing_cols.empty?
|
118
|
+
end
|
119
|
+
|
120
|
+
unless missing_pk_override.empty?
|
121
|
+
msg = missing_pk_override.collect {|tbl, cols|
|
122
|
+
"#{tbl} (#{cols.join(',')})"
|
123
|
+
}.join(', ')
|
124
|
+
raise self.class::COMPATIBILITY_ERROR_CLASS,
|
125
|
+
"Columns set as primary key don't exist. " +
|
126
|
+
"Set correct column names to these tables in \"#{table_schema}\" #{word_for_table_schema}: #{msg}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -1,47 +1,32 @@
|
|
1
1
|
require 'flydata-core/errors'
|
2
2
|
require 'flydata-core/mysql/config'
|
3
|
+
require 'flydata-core/compatibility_check/db_compatibility_checker'
|
3
4
|
require 'mysql2'
|
4
5
|
|
5
6
|
module FlydataCore
|
6
7
|
module Mysql
|
7
|
-
class
|
8
|
-
|
9
|
-
option ||= {}
|
10
|
-
@option = option.merge FlydataCore::Mysql::Config.build_mysql_db_opts(option)
|
11
|
-
end
|
8
|
+
class MysqlCompatibilityChecker < FlydataCore::CompatibilityCheck::DbCompatibilityChecker
|
9
|
+
COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError
|
12
10
|
|
13
|
-
def
|
14
|
-
|
15
|
-
check_result(result, option)
|
11
|
+
def initialize(option = {})
|
12
|
+
super(option.merge FlydataCore::Mysql::Config.build_mysql_db_opts(option))
|
16
13
|
end
|
17
14
|
|
18
15
|
# Override
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# Override
|
23
|
-
#def validate_result(result, option = @option)
|
24
|
-
#end
|
25
|
-
end
|
16
|
+
def build_db_client(option)
|
17
|
+
Mysql2::Client.new(@option)
|
18
|
+
end
|
26
19
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
else
|
33
|
-
exec_query(query)
|
34
|
-
end
|
35
|
-
check_result(result, option)
|
20
|
+
def schema_and_table_in_query(option = @option)
|
21
|
+
{
|
22
|
+
schema_name: "'#{option[:database]}'",
|
23
|
+
table_names: table_names_in_query(option[:tables]),
|
24
|
+
}
|
36
25
|
end
|
37
26
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
client.query(query)
|
42
|
-
ensure
|
43
|
-
client.close rescue nil if client
|
44
|
-
end
|
27
|
+
# "table_schema" is equivalent to "database" on MySQL. No schema notion inside database.
|
28
|
+
def word_for_table_schema
|
29
|
+
"database"
|
45
30
|
end
|
46
31
|
|
47
32
|
# This command works only on RDS MySQL
|
@@ -221,29 +206,20 @@ module FlydataCore
|
|
221
206
|
end
|
222
207
|
|
223
208
|
class TableExistenceChecker < MysqlCompatibilityChecker
|
209
|
+
include FlydataCore::CompatibilityCheck::TableExistenceCheck
|
224
210
|
TABLE_EXISTENCE_CHECK_QUERY_TMPLT = <<EOT
|
225
211
|
SELECT
|
226
|
-
t.
|
212
|
+
t.table_schema,
|
213
|
+
t.table_name
|
227
214
|
FROM
|
228
215
|
information_schema.tables t
|
229
216
|
WHERE
|
230
|
-
t.table_schema=
|
231
|
-
AND
|
217
|
+
t.table_schema = %{schema_name}
|
218
|
+
AND
|
219
|
+
t.table_name in (%{table_names})
|
220
|
+
UNION
|
221
|
+
SELECT %{schema_name}, '';
|
232
222
|
EOT
|
233
|
-
def create_query(option = @option)
|
234
|
-
TABLE_EXISTENCE_CHECK_QUERY_TMPLT % {database: option[:database], table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')}
|
235
|
-
end
|
236
|
-
|
237
|
-
def check_result(result, option = @option)
|
238
|
-
existing_tables = []
|
239
|
-
result.each {|r| existing_tables << r['table_name']}
|
240
|
-
missing_tables = option[:tables] - existing_tables
|
241
|
-
|
242
|
-
unless missing_tables.empty?
|
243
|
-
raise FlydataCore::MysqlCompatibilityError,
|
244
|
-
"These tables are missing. Create these tables on your database or remove them from the data entry : #{missing_tables.join(", ")}"
|
245
|
-
end
|
246
|
-
end
|
247
223
|
end
|
248
224
|
|
249
225
|
class MySqlVersion57CompabilityChecker < MysqlCompatibilityChecker
|
@@ -298,45 +274,46 @@ EOT
|
|
298
274
|
end
|
299
275
|
|
300
276
|
class PrimaryKeyChecker < MysqlCompatibilityChecker
|
277
|
+
include FlydataCore::CompatibilityCheck::PrimaryKeyCheck
|
301
278
|
PK_CHECK_QUERY_TMPLT = <<EOT
|
302
279
|
SELECT
|
280
|
+
t.table_schema,
|
303
281
|
t.table_name,
|
304
282
|
SUM(IF(tc.constraint_type='PRIMARY KEY' AND col.is_nullable='NO', 1, 0)) as num_pk,
|
305
283
|
SUM(IF(tc.constraint_type='UNIQUE' AND col.is_nullable='NO', 1, 0)) as num_uk
|
306
284
|
FROM
|
307
|
-
(select * from information_schema.tables where table_schema =
|
285
|
+
(select * from information_schema.tables where table_schema = %{schema_name} AND table_name in (%{table_names})) t
|
308
286
|
LEFT OUTER JOIN
|
309
|
-
(select * from information_schema.table_constraints where table_schema =
|
287
|
+
(select * from information_schema.table_constraints where table_schema = %{schema_name} AND table_name in (%{table_names})) tc
|
310
288
|
USING (table_schema, table_name)
|
311
289
|
LEFT JOIN
|
312
|
-
(select * from information_schema.key_column_usage where constraint_schema =
|
290
|
+
(select * from information_schema.key_column_usage where constraint_schema = %{schema_name}) kc
|
313
291
|
USING (table_schema, table_name, constraint_name)
|
314
292
|
LEFT JOIN
|
315
|
-
(select * from information_schema.columns where table_schema =
|
293
|
+
(select * from information_schema.columns where table_schema = %{schema_name} AND table_name in (%{table_names})) col
|
316
294
|
ON t.table_schema = col.table_schema AND t.table_name = col.table_name AND kc.column_name = col.column_name
|
317
295
|
GROUP BY
|
318
296
|
t.table_schema, t.table_name
|
319
297
|
HAVING
|
320
298
|
num_pk = 0 and num_uk = 0;
|
321
299
|
EOT
|
300
|
+
end
|
322
301
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
end
|
339
|
-
end
|
302
|
+
class PkOverrideChecker < MysqlCompatibilityChecker
|
303
|
+
include FlydataCore::CompatibilityCheck::PkOverrideCheck
|
304
|
+
PK_OVERRIDE_QUERY_TMPLT = <<EOT
|
305
|
+
SELECT
|
306
|
+
t.table_schema,
|
307
|
+
t.table_name,
|
308
|
+
col.column_name
|
309
|
+
FROM
|
310
|
+
(select * from information_schema.tables where table_schema = %{schema_name} AND table_name in (%{table_names})) t
|
311
|
+
LEFT JOIN
|
312
|
+
(select * from information_schema.columns where table_schema = %{schema_name} AND table_name in (%{table_names})) col
|
313
|
+
ON t.table_schema = col.table_schema AND t.table_name = col.table_name
|
314
|
+
ORDER BY
|
315
|
+
t.table_name;
|
316
|
+
EOT
|
340
317
|
end
|
341
318
|
|
342
319
|
class NonRdsRetentionChecker < MysqlCompatibilityChecker
|
@@ -1,114 +1,105 @@
|
|
1
1
|
require 'flydata-core/errors'
|
2
|
+
require 'flydata-core/postgresql/config'
|
3
|
+
require 'flydata-core/compatibility_check/db_compatibility_checker'
|
2
4
|
require 'flydata-core/postgresql/pg_client'
|
3
5
|
|
4
6
|
module FlydataCore
|
5
7
|
module Postgresql
|
6
|
-
class
|
7
|
-
|
8
|
-
option ||= {}
|
9
|
-
@option = option.merge FlydataCore::Postgresql::Config.build_db_opts(option)
|
10
|
-
end
|
8
|
+
class PostgresqlCompatibilityChecker < FlydataCore::CompatibilityCheck::DbCompatibilityChecker
|
9
|
+
COMPATIBILITY_ERROR_CLASS = PostgresqlCompatibilityError
|
11
10
|
|
12
|
-
def
|
13
|
-
|
14
|
-
check_result(result, option)
|
11
|
+
def initialize(option = {})
|
12
|
+
super(option.merge FlydataCore::Postgresql::Config.build_db_opts(option))
|
15
13
|
end
|
16
14
|
|
17
15
|
# Override
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
# Override
|
22
|
-
#def validate_result(result, option = @option)
|
23
|
-
#end
|
24
|
-
end
|
25
|
-
|
26
|
-
class PostgresqlCompatibilityChecker < CompatibilityChecker
|
27
|
-
def do_check(option = @option, &block)
|
28
|
-
query = create_query(option)
|
29
|
-
result = if block
|
30
|
-
block.call query
|
31
|
-
else
|
32
|
-
exec_query(query)
|
33
|
-
end
|
34
|
-
check_result(result, option)
|
35
|
-
end
|
36
|
-
|
37
|
-
def exec_query(query)
|
38
|
-
begin
|
39
|
-
client = PGClient.new(@option)
|
40
|
-
client.query(query)
|
41
|
-
ensure
|
42
|
-
client.close rescue nil if client
|
43
|
-
end
|
16
|
+
def build_db_client(option)
|
17
|
+
PGClient.new(@option)
|
44
18
|
end
|
45
19
|
|
46
20
|
def schema_and_table_in_query(option = @option)
|
47
21
|
schema = FlydataCore::Postgresql::QueryHelper.schema_as_value(option[:schema])
|
48
22
|
{
|
49
23
|
schema_name: schema,
|
50
|
-
table_names: option[:tables]
|
24
|
+
table_names: table_names_in_query(option[:tables]),
|
51
25
|
}
|
52
26
|
end
|
53
27
|
end
|
54
28
|
|
55
|
-
class
|
56
|
-
|
29
|
+
class SnapshotFunctionChecker < PostgresqlCompatibilityChecker
|
30
|
+
TXID_CURRENT_SNAPSHOT_CHECK_SQL = <<EOS
|
57
31
|
SELECT
|
58
|
-
|
32
|
+
p.proname
|
59
33
|
FROM
|
60
|
-
|
34
|
+
pg_proc p
|
35
|
+
JOIN pg_namespace n ON p.pronamespace = n.oid
|
61
36
|
WHERE
|
62
|
-
|
63
|
-
AND
|
64
|
-
|
65
|
-
EOT
|
37
|
+
n.nspname = 'pg_catalog'
|
38
|
+
AND p.proname = 'txid_current_snapshot';
|
39
|
+
EOS
|
66
40
|
|
67
41
|
def create_query(option = @option)
|
68
|
-
|
42
|
+
TXID_CURRENT_SNAPSHOT_CHECK_SQL
|
69
43
|
end
|
70
44
|
|
71
45
|
def check_result(result, option = @option)
|
72
|
-
|
73
|
-
result.each {|r| existing_tables << r['table_name']}
|
74
|
-
missing_tables = option[:tables] - existing_tables
|
75
|
-
|
76
|
-
unless missing_tables.empty?
|
46
|
+
unless result.first
|
77
47
|
raise FlydataCore::PostgresqlCompatibilityError,
|
78
|
-
"
|
48
|
+
"Unsupported PostgreSQL version. The version must be 8.3 or later."
|
79
49
|
end
|
80
50
|
end
|
81
51
|
end
|
82
52
|
|
53
|
+
class TableExistenceChecker < PostgresqlCompatibilityChecker
|
54
|
+
include FlydataCore::CompatibilityCheck::TableExistenceCheck
|
55
|
+
TABLE_EXISTENCE_CHECK_QUERY_TMPLT = <<EOT
|
56
|
+
SELECT
|
57
|
+
table_schema,
|
58
|
+
table_name
|
59
|
+
FROM
|
60
|
+
information_schema.tables
|
61
|
+
WHERE
|
62
|
+
table_schema = %{schema_name}
|
63
|
+
AND
|
64
|
+
table_name in (%{table_names})
|
65
|
+
UNION
|
66
|
+
SELECT %{schema_name}, '';
|
67
|
+
EOT
|
68
|
+
end
|
69
|
+
|
83
70
|
class PrimaryKeyChecker < PostgresqlCompatibilityChecker
|
71
|
+
include FlydataCore::CompatibilityCheck::PrimaryKeyCheck
|
84
72
|
PK_CHECK_QUERY_TMPLT = <<EOT
|
85
73
|
SELECT
|
74
|
+
t.table_schema,
|
86
75
|
t.table_name
|
87
76
|
FROM
|
88
|
-
(select * from information_schema.tables where table_schema
|
77
|
+
(select * from information_schema.tables where table_schema = %{schema_name} AND table_name in (%{table_names})) t
|
89
78
|
LEFT OUTER JOIN
|
90
|
-
(select * from information_schema.table_constraints where table_schema
|
79
|
+
(select * from information_schema.table_constraints where table_schema = %{schema_name} AND table_name in (%{table_names})) tc
|
91
80
|
USING (table_schema, table_name)
|
92
81
|
GROUP BY
|
93
82
|
t.table_schema, t.table_name
|
94
83
|
HAVING
|
95
84
|
SUM(CASE WHEN tc.constraint_type='PRIMARY KEY' THEN 1 ELSE 0 END) = 0;
|
96
85
|
EOT
|
86
|
+
end
|
97
87
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
88
|
+
class PkOverrideChecker < PostgresqlCompatibilityChecker
|
89
|
+
include FlydataCore::CompatibilityCheck::PkOverrideCheck
|
90
|
+
PK_OVERRIDE_QUERY_TMPLT = <<EOT
|
91
|
+
SELECT
|
92
|
+
t.table_schema,
|
93
|
+
t.table_name,
|
94
|
+
col.column_name
|
95
|
+
FROM
|
96
|
+
(select * from information_schema.tables where table_schema = %{schema_name} AND table_name in (%{table_names})) t
|
97
|
+
LEFT JOIN
|
98
|
+
(select * from information_schema.columns where table_schema = %{schema_name} AND table_name in (%{table_names})) col
|
99
|
+
ON t.table_schema = col.table_schema AND t.table_name = col.table_name
|
100
|
+
ORDER BY
|
101
|
+
t.table_name;
|
102
|
+
EOT
|
112
103
|
end
|
113
104
|
end
|
114
105
|
end
|
@@ -3,7 +3,7 @@ require 'flydata-core/mysql/compatibility_checker'
|
|
3
3
|
|
4
4
|
module FlydataCore
|
5
5
|
module Mysql
|
6
|
-
describe CompatibilityChecker do
|
6
|
+
describe 'CompatibilityChecker' do
|
7
7
|
let(:database) { 'test_db' }
|
8
8
|
let(:mysql_host) { hostname + '.' + domain_name }
|
9
9
|
let(:hostname) { 'test-hostname' }
|
@@ -87,12 +87,16 @@ module FlydataCore
|
|
87
87
|
subject { subject_object.create_query }
|
88
88
|
it { is_expected.to eq <<EOT
|
89
89
|
SELECT
|
90
|
-
t.
|
90
|
+
t.table_schema,
|
91
|
+
t.table_name
|
91
92
|
FROM
|
92
93
|
information_schema.tables t
|
93
94
|
WHERE
|
94
|
-
t.table_schema='test_db'
|
95
|
-
AND
|
95
|
+
t.table_schema = 'test_db'
|
96
|
+
AND
|
97
|
+
t.table_name in ('table_1','table_2','table_3')
|
98
|
+
UNION
|
99
|
+
SELECT 'test_db', '';
|
96
100
|
EOT
|
97
101
|
}
|
98
102
|
end
|
@@ -133,6 +137,7 @@ EOT
|
|
133
137
|
subject { subject_object.create_query }
|
134
138
|
it { is_expected.to eq <<EOT
|
135
139
|
SELECT
|
140
|
+
t.table_schema,
|
136
141
|
t.table_name,
|
137
142
|
SUM(IF(tc.constraint_type='PRIMARY KEY' AND col.is_nullable='NO', 1, 0)) as num_pk,
|
138
143
|
SUM(IF(tc.constraint_type='UNIQUE' AND col.is_nullable='NO', 1, 0)) as num_uk
|
@@ -162,6 +167,7 @@ EOT
|
|
162
167
|
end
|
163
168
|
it { is_expected.to eq <<EOT
|
164
169
|
SELECT
|
170
|
+
t.table_schema,
|
165
171
|
t.table_name,
|
166
172
|
SUM(IF(tc.constraint_type='PRIMARY KEY' AND col.is_nullable='NO', 1, 0)) as num_pk,
|
167
173
|
SUM(IF(tc.constraint_type='UNIQUE' AND col.is_nullable='NO', 1, 0)) as num_uk
|
@@ -221,6 +227,81 @@ EOT
|
|
221
227
|
end
|
222
228
|
end
|
223
229
|
end
|
230
|
+
|
231
|
+
describe PkOverrideChecker do
|
232
|
+
let(:subject_object) { described_class.new(option) }
|
233
|
+
|
234
|
+
describe '#create_query' do
|
235
|
+
subject { subject_object.create_query }
|
236
|
+
|
237
|
+
context 'when pk_override is given' do
|
238
|
+
before do
|
239
|
+
option[:pk_override] = {
|
240
|
+
'table_1' => ['id'],
|
241
|
+
'table_2' => ['name'],
|
242
|
+
}
|
243
|
+
end
|
244
|
+
it { is_expected.to eq <<EOT
|
245
|
+
SELECT
|
246
|
+
t.table_schema,
|
247
|
+
t.table_name,
|
248
|
+
col.column_name
|
249
|
+
FROM
|
250
|
+
(select * from information_schema.tables where table_schema = 'test_db' AND table_name in ('table_1','table_2')) t
|
251
|
+
LEFT JOIN
|
252
|
+
(select * from information_schema.columns where table_schema = 'test_db' AND table_name in ('table_1','table_2')) col
|
253
|
+
ON t.table_schema = col.table_schema AND t.table_name = col.table_name
|
254
|
+
ORDER BY
|
255
|
+
t.table_name;
|
256
|
+
EOT
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'when no pk override' do
|
261
|
+
let(:tables) { %w(table_2) }
|
262
|
+
before do
|
263
|
+
option.delete(:pk_override)
|
264
|
+
end
|
265
|
+
it { is_expected.to be_nil }
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
describe '#check_reesult' do
|
270
|
+
subject { subject_object.check_result(result) }
|
271
|
+
let(:result) { [
|
272
|
+
{"table_name" => "table_1", "column_name" => "id"},
|
273
|
+
{"table_name" => "table_1", "column_name" => "value"},
|
274
|
+
{"table_name" => "table_2", "column_name" => "name"},
|
275
|
+
{"table_name" => "table_2", "column_name" => "age"},
|
276
|
+
] }
|
277
|
+
|
278
|
+
before do
|
279
|
+
option[:pk_override] = pk_override
|
280
|
+
end
|
281
|
+
|
282
|
+
context 'when given pk_override exist' do
|
283
|
+
let(:pk_override) { {
|
284
|
+
'table_1' => ['id'],
|
285
|
+
'table_2' => ['name'],
|
286
|
+
} }
|
287
|
+
it { expect{subject}.not_to raise_error }
|
288
|
+
end
|
289
|
+
|
290
|
+
context 'when some columns do not exist' do
|
291
|
+
let(:pk_override) { {
|
292
|
+
'table_1' => ['id'],
|
293
|
+
'table_2' => ['id'],
|
294
|
+
} }
|
295
|
+
it do
|
296
|
+
expect{subject}.to raise_error {|e|
|
297
|
+
expect(e).to be_kind_of(FlydataCore::MysqlCompatibilityError)
|
298
|
+
expect(e.to_s.include?("table_1")).to be_falsey
|
299
|
+
expect(e.to_s.include?("table_2")).to be_truthy
|
300
|
+
}
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
224
305
|
end
|
225
306
|
|
226
307
|
describe BinlogParameterChecker do
|
@@ -3,13 +3,43 @@ require 'flydata-core/postgresql/compatibility_checker'
|
|
3
3
|
|
4
4
|
module FlydataCore
|
5
5
|
module Postgresql
|
6
|
-
describe CompatibilityChecker do
|
6
|
+
describe 'CompatibilityChecker' do
|
7
7
|
let(:database) { 'test_db' }
|
8
8
|
let(:tables) { %w(table_1 table_2 table_3) }
|
9
9
|
let(:option) do
|
10
10
|
{ database: database, tables: tables }
|
11
11
|
end
|
12
12
|
|
13
|
+
describe SnapshotFunctionChecker do
|
14
|
+
let(:subject_object) { described_class.new(option) }
|
15
|
+
|
16
|
+
describe '#check_reesult' do
|
17
|
+
let(:result) { [] }
|
18
|
+
subject { subject_object.check_result(result) }
|
19
|
+
|
20
|
+
context 'when the function exists' do
|
21
|
+
let(:result) do
|
22
|
+
[ {'proname' => 'txid_current_snapshot'} ]
|
23
|
+
end
|
24
|
+
it { expect{subject}.not_to raise_error }
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when the function does not exist' do
|
28
|
+
let(:result) do
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
it do
|
32
|
+
expect{subject}.to raise_error(
|
33
|
+
FlydataCore::PostgresqlCompatibilityError,
|
34
|
+
/Unsupported PostgreSQL version/
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
13
43
|
describe TableExistenceChecker do
|
14
44
|
let(:subject_object) { described_class.new(option) }
|
15
45
|
|
@@ -19,13 +49,16 @@ module FlydataCore
|
|
19
49
|
context 'when schema is not set' do
|
20
50
|
it { is_expected.to eq <<EOT
|
21
51
|
SELECT
|
52
|
+
table_schema,
|
22
53
|
table_name
|
23
54
|
FROM
|
24
55
|
information_schema.tables
|
25
56
|
WHERE
|
26
|
-
table_schema
|
57
|
+
table_schema = (select current_schema)
|
27
58
|
AND
|
28
|
-
table_name in ('table_1','table_2','table_3')
|
59
|
+
table_name in ('table_1','table_2','table_3')
|
60
|
+
UNION
|
61
|
+
SELECT (select current_schema), '';
|
29
62
|
EOT
|
30
63
|
}
|
31
64
|
end
|
@@ -33,13 +66,16 @@ EOT
|
|
33
66
|
before { option.merge!(schema: 'test_schema') }
|
34
67
|
it { is_expected.to eq <<EOT
|
35
68
|
SELECT
|
69
|
+
table_schema,
|
36
70
|
table_name
|
37
71
|
FROM
|
38
72
|
information_schema.tables
|
39
73
|
WHERE
|
40
|
-
table_schema
|
74
|
+
table_schema = 'test_schema'
|
41
75
|
AND
|
42
|
-
table_name in ('table_1','table_2','table_3')
|
76
|
+
table_name in ('table_1','table_2','table_3')
|
77
|
+
UNION
|
78
|
+
SELECT 'test_schema', '';
|
43
79
|
EOT
|
44
80
|
}
|
45
81
|
end
|
@@ -84,11 +120,12 @@ EOT
|
|
84
120
|
context 'when schema is not set' do
|
85
121
|
it { is_expected.to eq <<EOT
|
86
122
|
SELECT
|
123
|
+
t.table_schema,
|
87
124
|
t.table_name
|
88
125
|
FROM
|
89
|
-
(select * from information_schema.tables where table_schema
|
126
|
+
(select * from information_schema.tables where table_schema = (select current_schema) AND table_name in ('table_1','table_2','table_3')) t
|
90
127
|
LEFT OUTER JOIN
|
91
|
-
(select * from information_schema.table_constraints where table_schema
|
128
|
+
(select * from information_schema.table_constraints where table_schema = (select current_schema) AND table_name in ('table_1','table_2','table_3')) tc
|
92
129
|
USING (table_schema, table_name)
|
93
130
|
GROUP BY
|
94
131
|
t.table_schema, t.table_name
|
@@ -102,11 +139,12 @@ EOT
|
|
102
139
|
before { option.merge!(schema: 'test_schema') }
|
103
140
|
it { is_expected.to eq <<EOT
|
104
141
|
SELECT
|
142
|
+
t.table_schema,
|
105
143
|
t.table_name
|
106
144
|
FROM
|
107
|
-
(select * from information_schema.tables where table_schema
|
145
|
+
(select * from information_schema.tables where table_schema = 'test_schema' AND table_name in ('table_1','table_2','table_3')) t
|
108
146
|
LEFT OUTER JOIN
|
109
|
-
(select * from information_schema.table_constraints where table_schema
|
147
|
+
(select * from information_schema.table_constraints where table_schema = 'test_schema' AND table_name in ('table_1','table_2','table_3')) tc
|
110
148
|
USING (table_schema, table_name)
|
111
149
|
GROUP BY
|
112
150
|
t.table_schema, t.table_name
|
@@ -117,7 +155,7 @@ EOT
|
|
117
155
|
end
|
118
156
|
end
|
119
157
|
|
120
|
-
describe '#
|
158
|
+
describe '#check_result' do
|
121
159
|
let(:result) { [] }
|
122
160
|
subject { subject_object.check_result(result) }
|
123
161
|
|
@@ -133,6 +171,7 @@ EOT
|
|
133
171
|
[{"table_name" => "table_1"}, {"table_name" => "table_3"}]
|
134
172
|
end
|
135
173
|
it do
|
174
|
+
skip "Primary key check for postgresql currenlty not raises error due to false alarm"
|
136
175
|
expect{subject}.to raise_error {|e|
|
137
176
|
expect(e).to be_kind_of(FlydataCore::PostgresqlCompatibilityError)
|
138
177
|
expect(e.to_s.include?("table_1")).to be_truthy
|
@@ -143,6 +182,81 @@ EOT
|
|
143
182
|
end
|
144
183
|
end
|
145
184
|
end
|
185
|
+
|
186
|
+
describe PkOverrideChecker do
|
187
|
+
let(:subject_object) { described_class.new(option) }
|
188
|
+
|
189
|
+
describe '#create_query' do
|
190
|
+
subject { subject_object.create_query }
|
191
|
+
|
192
|
+
context 'when pk_override is given' do
|
193
|
+
before do
|
194
|
+
option[:pk_override] = {
|
195
|
+
'table_1' => ['id'],
|
196
|
+
'table_2' => ['name'],
|
197
|
+
}
|
198
|
+
end
|
199
|
+
it { is_expected.to eq <<EOT
|
200
|
+
SELECT
|
201
|
+
t.table_schema,
|
202
|
+
t.table_name,
|
203
|
+
col.column_name
|
204
|
+
FROM
|
205
|
+
(select * from information_schema.tables where table_schema = (select current_schema) AND table_name in ('table_1','table_2')) t
|
206
|
+
LEFT JOIN
|
207
|
+
(select * from information_schema.columns where table_schema = (select current_schema) AND table_name in ('table_1','table_2')) col
|
208
|
+
ON t.table_schema = col.table_schema AND t.table_name = col.table_name
|
209
|
+
ORDER BY
|
210
|
+
t.table_name;
|
211
|
+
EOT
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'when no pk override' do
|
216
|
+
let(:tables) { %w(table_2) }
|
217
|
+
before do
|
218
|
+
option.delete(:pk_override)
|
219
|
+
end
|
220
|
+
it { is_expected.to be_nil }
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '#check_reesult' do
|
225
|
+
subject { subject_object.check_result(result) }
|
226
|
+
let(:result) { [
|
227
|
+
{"table_name" => "table_1", "column_name" => "id"},
|
228
|
+
{"table_name" => "table_1", "column_name" => "value"},
|
229
|
+
{"table_name" => "table_2", "column_name" => "name"},
|
230
|
+
{"table_name" => "table_2", "column_name" => "age"},
|
231
|
+
] }
|
232
|
+
|
233
|
+
before do
|
234
|
+
option[:pk_override] = pk_override
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'when given pk_override exist' do
|
238
|
+
let(:pk_override) { {
|
239
|
+
'table_1' => ['id'],
|
240
|
+
'table_2' => ['name'],
|
241
|
+
} }
|
242
|
+
it { expect{subject}.not_to raise_error }
|
243
|
+
end
|
244
|
+
|
245
|
+
context 'when some columns do not exist' do
|
246
|
+
let(:pk_override) { {
|
247
|
+
'table_1' => ['id'],
|
248
|
+
'table_2' => ['id'],
|
249
|
+
} }
|
250
|
+
it do
|
251
|
+
expect{subject}.to raise_error {|e|
|
252
|
+
expect(e).to be_kind_of(FlydataCore::PostgresqlCompatibilityError)
|
253
|
+
expect(e.to_s.include?("table_1")).to be_falsey
|
254
|
+
expect(e.to_s.include?("table_2")).to be_truthy
|
255
|
+
}
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
146
260
|
end
|
147
261
|
end
|
148
262
|
end
|
data/flydata.gemspec
CHANGED
Binary file
|
@@ -17,9 +17,14 @@ module PluginSupport
|
|
17
17
|
|
18
18
|
def process(record)
|
19
19
|
if acceptable_db?(record)
|
20
|
-
|
20
|
+
emit_record(:create_table, record) do |opt|
|
21
|
+
table_name = table_info(record)[:table_name]
|
22
|
+
$log.info "type:create_table table_name:'#{table_name}' query:'#{record["query"]}' binlog_pos:'#{binlog_pos(record)}'"
|
23
|
+
|
24
|
+
opt[:increment_table_rev] = true
|
25
|
+
{ table_name: table_name, query: record["query"] }
|
26
|
+
end
|
21
27
|
end
|
22
|
-
#NOTE: No emit_record here because this record should not be sent to data servers for now
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
@@ -17,9 +17,14 @@ module PluginSupport
|
|
17
17
|
|
18
18
|
def process(record)
|
19
19
|
if acceptable_db?(record)
|
20
|
-
|
20
|
+
emit_record(:drop_table, record) do |opt|
|
21
|
+
table_name = table_info(record)[:table_name]
|
22
|
+
$log.info "type:drop_table table_name:'#{table_name}' query:'#{record["query"]}' binlog_pos:'#{binlog_pos(record)}'"
|
23
|
+
|
24
|
+
opt[:increment_table_rev] = true
|
25
|
+
{ table_name: table_name, query: record["query"] }
|
26
|
+
end
|
21
27
|
end
|
22
|
-
#NOTE: No emit_record here because this record should not be sent to data servers for now
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
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.7.
|
4
|
+
version: 0.7.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: 2016-08-
|
15
|
+
date: 2016-08-09 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rest-client
|
@@ -522,6 +522,8 @@ files:
|
|
522
522
|
- flydata-core/circle.yml
|
523
523
|
- flydata-core/lib/flydata-core.rb
|
524
524
|
- flydata-core/lib/flydata-core/agent.rb
|
525
|
+
- flydata-core/lib/flydata-core/compatibility_check/base.rb
|
526
|
+
- flydata-core/lib/flydata-core/compatibility_check/db_compatibility_checker.rb
|
525
527
|
- flydata-core/lib/flydata-core/config/user_maintenance.rb
|
526
528
|
- flydata-core/lib/flydata-core/core_ext.rb
|
527
529
|
- flydata-core/lib/flydata-core/core_ext/module.rb
|
@@ -880,7 +882,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
880
882
|
version: '0'
|
881
883
|
requirements: []
|
882
884
|
rubyforge_project:
|
883
|
-
rubygems_version: 2.
|
885
|
+
rubygems_version: 2.4.3
|
884
886
|
signing_key:
|
885
887
|
specification_version: 4
|
886
888
|
summary: FlyData Agent
|