flydata 0.7.0 → 0.7.1
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/ext/flydata/source_mysql/parser/sql_parser.cpp +25 -25
- data/flydata-core/lib/flydata-core/postgresql/compatibility_checker.rb +4 -9
- data/flydata-core/lib/flydata-core/postgresql/pg_client.rb +1 -0
- data/flydata-core/lib/flydata-core/postgresql/query_helper.rb +17 -0
- data/flydata-core/lib/flydata-core/postgresql/snapshot.rb +11 -0
- data/flydata-core/lib/flydata-core/postgresql/source_pos.rb +4 -0
- data/flydata-core/lib/flydata-core/table_def/postgresql_table_def.rb +6 -6
- data/flydata-core/lib/flydata-core/table_def/redshift_table_def.rb +25 -26
- data/flydata-core/lib/flydata-core/table_def/value_conv.rb +29 -0
- data/flydata-core/spec/postgresql/compatibility_checker_spec.rb +3 -3
- data/flydata-core/spec/postgresql/query_helper_spec.rb +29 -0
- data/flydata-core/spec/postgresql/snapshot_spec.rb +25 -0
- data/flydata-core/spec/table_def/redshift_table_def_spec.rb +59 -7
- data/flydata-core/spec/table_def/value_conv_spec.rb +33 -0
- data/flydata.gemspec +0 -0
- data/lib/flydata/fluent-plugins/in_mysql_binlog_flydata.rb +1 -1
- data/lib/flydata/source_mysql/data_entry.rb +1 -0
- data/lib/flydata/source_postgresql/command/psql.rb +48 -0
- data/lib/flydata/source_postgresql/data_entry.rb +1 -0
- data/lib/flydata/source_postgresql/generate_source_dump.rb +10 -7
- data/lib/flydata/source_postgresql/query_based_sync/diff_query_generator.rb +9 -2
- data/lib/flydata/source_postgresql/table_meta.rb +7 -3
- data/spec/flydata/fluent-plugins/in_mysql_binlog_flydata_spec.rb +1 -0
- data/spec/flydata/fluent-plugins/in_postgresql_query_based_flydata_spec.rb +2 -1
- data/spec/flydata/source_postgresql/query_based_sync/diff_query_generator_spec.rb +45 -11
- data/spec/flydata/source_postgresql/table_meta_spec.rb +19 -0
- data/tmpl/redshift_postgresql_data_entry.conf.tmpl +13 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c1e7d064581a7d76441fa77bc814c1ebba986cd
|
4
|
+
data.tar.gz: bb14ff1bbf83246092ddbc44332dadc42725e1f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3fee3b20cdb7ef01f45a05d3485e637fcb794c15c4bb31e2027535241db6ee31de9c7b97e8b5a4ab1892b415a1a26a336c525d8a9a19b960c2d4b5e5677006e
|
7
|
+
data.tar.gz: 477339f6ca63c80d13a9d499e062c5e42cae23a99a24d058f37fdbea01829084c9f137e7c00baa88bc56ff5389fd858119fc2c4ce1583358505e9dd7bfac4d05
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#include <iostream>
|
2
2
|
#include "sql_parser.h"
|
3
3
|
|
4
|
-
|
4
|
+
#define DEBUG 0
|
5
5
|
|
6
6
|
enum status_t {
|
7
7
|
start,
|
@@ -54,7 +54,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
54
54
|
break;
|
55
55
|
|
56
56
|
case value:
|
57
|
-
if (
|
57
|
+
if (DEBUG) std::cout << "value[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
58
58
|
if (*current == '\'') {
|
59
59
|
status = first_char;
|
60
60
|
} else if (*current == 'N') {
|
@@ -76,7 +76,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
76
76
|
break;
|
77
77
|
|
78
78
|
case first_zero:
|
79
|
-
if (
|
79
|
+
if (DEBUG) std::cout << "first_zero[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
80
80
|
if (*current == ',') {
|
81
81
|
ch.value_callback(mark, value_len - 1, true);//value_callback :end_value
|
82
82
|
mark = 0; value_len = 0; //mark_reset
|
@@ -102,7 +102,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
102
102
|
break;
|
103
103
|
|
104
104
|
case leading_zero:
|
105
|
-
if (
|
105
|
+
if (DEBUG) std::cout << "leading_zero[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
106
106
|
if (*current == ',') {
|
107
107
|
ch.value_callback(mark, value_len - 1, true);//value_callback :end_value
|
108
108
|
mark = 0; value_len = 0; //mark_reset
|
@@ -126,7 +126,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
126
126
|
break;
|
127
127
|
|
128
128
|
case number:
|
129
|
-
if (
|
129
|
+
if (DEBUG) std::cout << "number[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
130
130
|
if ((*current >= '0' && *current <= '9') || *current == '.' || *current == 'e' || *current == 'E' || *current == '-') {
|
131
131
|
status = number;
|
132
132
|
} else if (*current == ',') {
|
@@ -144,7 +144,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
144
144
|
break;
|
145
145
|
|
146
146
|
case null_n:
|
147
|
-
if (
|
147
|
+
if (DEBUG) std::cout << "null_n[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
148
148
|
if (*current == 'U') {
|
149
149
|
status = null_u;
|
150
150
|
} else {
|
@@ -153,7 +153,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
153
153
|
break;
|
154
154
|
|
155
155
|
case null_u:
|
156
|
-
if (
|
156
|
+
if (DEBUG) std::cout << "null_u[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
157
157
|
if (*current == 'L') {
|
158
158
|
status = null_l1;
|
159
159
|
} else {
|
@@ -162,7 +162,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
162
162
|
break;
|
163
163
|
|
164
164
|
case null_l1:
|
165
|
-
if (
|
165
|
+
if (DEBUG) std::cout << "null_l1[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
166
166
|
if (*current == 'L') {
|
167
167
|
status = null_l2;
|
168
168
|
} else {
|
@@ -171,7 +171,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
171
171
|
break;
|
172
172
|
|
173
173
|
case null_l2:
|
174
|
-
if (
|
174
|
+
if (DEBUG) std::cout << "null_l2[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
175
175
|
if (*current == ',') {
|
176
176
|
//# 0 is NULL pointer
|
177
177
|
ch.value_callback(0, 0, true);//value_callback 0 :end_value
|
@@ -189,7 +189,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
189
189
|
break;
|
190
190
|
|
191
191
|
case hex_blob:
|
192
|
-
if (
|
192
|
+
if (DEBUG) std::cout << "hex_blob[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
193
193
|
if ((*current >= '0' && *current <= '9') ||
|
194
194
|
(*current >= 'A' && *current <= 'F') ||
|
195
195
|
(*current >= 'a' && *current <= 'f')) {
|
@@ -200,7 +200,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
200
200
|
break;
|
201
201
|
|
202
202
|
case hex_blob_number:
|
203
|
-
if (
|
203
|
+
if (DEBUG) std::cout << "hex_blob_number[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
204
204
|
if ((*current >= '0' && *current <= '9') ||
|
205
205
|
(*current >= 'A' && *current <= 'F') ||
|
206
206
|
(*current >= 'a' && *current <= 'f')) {
|
@@ -220,7 +220,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
220
220
|
break;
|
221
221
|
|
222
222
|
case first_char:
|
223
|
-
if (
|
223
|
+
if (DEBUG) std::cout << "first_char[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
224
224
|
if (*current == '\'') {
|
225
225
|
mark = current; value_len = 1; //mark
|
226
226
|
ch.value_callback(mark, value_len - 1, true);//value_callback, :end_value
|
@@ -248,7 +248,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
248
248
|
break;
|
249
249
|
|
250
250
|
case utf8_2_firstbyte:
|
251
|
-
if (
|
251
|
+
if (DEBUG) std::cout << "utf8_2_firstbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
252
252
|
if ((*current & 0xc0) == 0x80) {
|
253
253
|
temp_mark = 0; //temp_mark reset)
|
254
254
|
status = following_char;
|
@@ -262,7 +262,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
262
262
|
break;
|
263
263
|
|
264
264
|
case utf8_3_firstbyte:
|
265
|
-
if (
|
265
|
+
if (DEBUG) std::cout << "utf8_3_firstbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
266
266
|
if ((*current & 0xc0) == 0x80) {
|
267
267
|
status = utf8_3_secondbyte;
|
268
268
|
} else {
|
@@ -271,7 +271,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
271
271
|
break;
|
272
272
|
|
273
273
|
case utf8_3_secondbyte:
|
274
|
-
if (
|
274
|
+
if (DEBUG) std::cout << "utf8_3_secondbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
275
275
|
if ((*current & 0xc0) == 0x80) {
|
276
276
|
temp_mark = 0; //temp_mark reset)
|
277
277
|
status = following_char;
|
@@ -285,7 +285,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
285
285
|
break;
|
286
286
|
|
287
287
|
case utf8_3_err_secondbyte:
|
288
|
-
if (
|
288
|
+
if (DEBUG) std::cout << "utf8_3_err_secondbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
289
289
|
ch.value_callback(mark, temp_mark - mark, false);//value_callback mark...temp_mark
|
290
290
|
mark = 0; value_len = 0; //mark_reset
|
291
291
|
ch.value_callback("\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd", 9, false); //value_callback "\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd"
|
@@ -294,7 +294,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
294
294
|
break;
|
295
295
|
|
296
296
|
case utf8_4_firstbyte:
|
297
|
-
if (
|
297
|
+
if (DEBUG) std::cout << "utf8_4_firstbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
298
298
|
if ((*current & 0xc0) == 0x80) {
|
299
299
|
status = utf8_4_secondbyte;
|
300
300
|
} else {
|
@@ -303,7 +303,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
303
303
|
break;
|
304
304
|
|
305
305
|
case utf8_4_secondbyte:
|
306
|
-
if (
|
306
|
+
if (DEBUG) std::cout << "utf8_4_secondbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
307
307
|
if ((*current & 0xc0) == 0x80) {
|
308
308
|
status = utf8_4_thirdbyte;
|
309
309
|
} else {
|
@@ -312,12 +312,12 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
312
312
|
break;
|
313
313
|
|
314
314
|
case utf8_4_err_secondbyte:
|
315
|
-
if (
|
315
|
+
if (DEBUG) std::cout << "utf8_4_err_secondbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
316
316
|
status = utf8_4_err_thirdbyte;
|
317
317
|
break;
|
318
318
|
|
319
319
|
case utf8_4_thirdbyte:
|
320
|
-
if (
|
320
|
+
if (DEBUG) std::cout << "utf8_4_thirdbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
321
321
|
if ((*current & 0xc0) == 0x80) {
|
322
322
|
temp_mark = 0; //temp_mark reset)
|
323
323
|
status = following_char;
|
@@ -331,7 +331,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
331
331
|
break;
|
332
332
|
|
333
333
|
case utf8_4_err_thirdbyte:
|
334
|
-
if (
|
334
|
+
if (DEBUG) std::cout << "utf8_4_err_thirdbyte[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
335
335
|
ch.value_callback(mark, temp_mark - mark, false);//value_callback mark...temp_mark
|
336
336
|
mark = 0; value_len = 0; //mark_reset
|
337
337
|
ch.value_callback("\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd", 12, false); //value_callback "\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd"
|
@@ -340,7 +340,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
340
340
|
break;
|
341
341
|
|
342
342
|
case following_char:
|
343
|
-
if (
|
343
|
+
if (DEBUG) std::cout << "following_char[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
344
344
|
if (*current == '\'') {
|
345
345
|
ch.value_callback(mark, value_len - 1, true);//value_callback, :end_value
|
346
346
|
mark = 0; value_len = 0; //mark_reset
|
@@ -364,7 +364,7 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
364
364
|
break;
|
365
365
|
|
366
366
|
case escape:
|
367
|
-
if (
|
367
|
+
if (DEBUG) std::cout << "escape[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
368
368
|
if (*current == '\"') {
|
369
369
|
ch.value_callback("\"", 1, false);//value_callback '\"'
|
370
370
|
mark = 0; value_len = 0;
|
@@ -401,12 +401,12 @@ long parse_insert_query(const char* sql, long len, ParserCallbackHandler& ch)
|
|
401
401
|
break;
|
402
402
|
|
403
403
|
case error:
|
404
|
-
if (
|
404
|
+
if (DEBUG) std::cout << "error[" << *current << std::endl << std::flush;
|
405
405
|
ret = pos - 1;
|
406
406
|
break;
|
407
407
|
|
408
408
|
default:
|
409
|
-
if (
|
409
|
+
if (DEBUG) std::cout << "default[" << *current << "(0x" << std::hex << (*current & 0xff) << ")]: " << std::endl << std::flush;
|
410
410
|
break;
|
411
411
|
}//switch
|
412
412
|
if (ret != -1)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'flydata-core/errors'
|
2
|
-
require 'flydata-core/postgresql/
|
3
|
-
require 'pg'
|
2
|
+
require 'flydata-core/postgresql/pg_client'
|
4
3
|
|
5
4
|
module FlydataCore
|
6
5
|
module Postgresql
|
@@ -37,19 +36,15 @@ module FlydataCore
|
|
37
36
|
|
38
37
|
def exec_query(query)
|
39
38
|
begin
|
40
|
-
client =
|
41
|
-
client.
|
39
|
+
client = PGClient.new(@option)
|
40
|
+
client.query(query)
|
42
41
|
ensure
|
43
42
|
client.close rescue nil if client
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
46
|
def schema_and_table_in_query(option = @option)
|
48
|
-
schema =
|
49
|
-
"select current_schema"
|
50
|
-
else
|
51
|
-
"'#{option[:schema]}'"
|
52
|
-
end
|
47
|
+
schema = FlydataCore::Postgresql::QueryHelper.schema_as_value(option[:schema])
|
53
48
|
{
|
54
49
|
schema_name: schema,
|
55
50
|
table_names: option[:tables].collect{|tn| "'#{tn}'"}.join(',')
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FlydataCore
|
2
|
+
module Postgresql
|
3
|
+
|
4
|
+
class QueryHelper
|
5
|
+
# Return query getting a current_schema if schema is nil or empty
|
6
|
+
def self.schema_as_value(schema)
|
7
|
+
s = schema.to_s.strip
|
8
|
+
if s.empty?
|
9
|
+
'(select current_schema)'
|
10
|
+
else
|
11
|
+
"'#{s}'"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -11,6 +11,8 @@ class Snapshot
|
|
11
11
|
|
12
12
|
def initialize(txid_snapshot)
|
13
13
|
@txid_snapshot_str = txid_snapshot.to_s
|
14
|
+
|
15
|
+
return if self.empty?
|
14
16
|
xmin_str, xmax_str, xip_list_str = @txid_snapshot_str.split(':')
|
15
17
|
|
16
18
|
raise ArgumentError, "Invalid snapshot - xmin is empty." if xmin_str.to_s.empty?
|
@@ -27,7 +29,16 @@ class Snapshot
|
|
27
29
|
@txid_snapshot_str
|
28
30
|
end
|
29
31
|
|
32
|
+
def empty?
|
33
|
+
@txid_snapshot_str == '-'
|
34
|
+
end
|
35
|
+
|
30
36
|
def <=>(other)
|
37
|
+
return 0 if empty? && other.empty?
|
38
|
+
if self.empty? || other.empty?
|
39
|
+
raise ArgumentError.new("comparison with empty source pos failed")
|
40
|
+
end
|
41
|
+
|
31
42
|
if @xmin == other.xmin
|
32
43
|
if @xmax == other.xmax
|
33
44
|
# items xip_list will disappear after the transaction is completed,
|
@@ -10,8 +10,8 @@ class PostgresqlTableDef < Base
|
|
10
10
|
TYPE_MAP_P2F = {
|
11
11
|
'bigint' => {type: 'int8'},
|
12
12
|
'int8' => {type: 'int8'},
|
13
|
-
'bigserial' => {type: 'serial8'},
|
14
|
-
'serial8' => {type: 'serial8'},
|
13
|
+
'bigserial' => {type: 'serial8'},
|
14
|
+
'serial8' => {type: 'serial8'},
|
15
15
|
'bit' => {type: 'bit',
|
16
16
|
width_attrs:["character_maximum_length"]},
|
17
17
|
'bit varying' => {type: 'varbit',
|
@@ -55,10 +55,10 @@ class PostgresqlTableDef < Base
|
|
55
55
|
'float4' => {type: 'float4'},
|
56
56
|
'smallint' => {type: 'int2'},
|
57
57
|
'int2' => {type: 'int2'},
|
58
|
-
'smallserial' => {type: 'serial2'},
|
59
|
-
'serial2' => {type: 'serial2'},
|
60
|
-
'serial' => {type: 'serial4'},
|
61
|
-
'serial4' => {type: 'serial4'},
|
58
|
+
'smallserial' => {type: 'serial2'},
|
59
|
+
'serial2' => {type: 'serial2'},
|
60
|
+
'serial' => {type: 'serial4'},
|
61
|
+
'serial4' => {type: 'serial4'},
|
62
62
|
'text' => {type: 'text'},
|
63
63
|
'time' => {type: 'time'},
|
64
64
|
'time without time zone' => {type: 'time'},
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'flydata-core/errors'
|
3
|
+
require 'flydata-core/table_def/value_conv'
|
3
4
|
|
4
5
|
module FlydataCore
|
5
6
|
module TableDef
|
@@ -218,7 +219,7 @@ EOS
|
|
218
219
|
|
219
220
|
rs_type = if type_info[:use_params]
|
220
221
|
if params
|
221
|
-
params = check_and_replace_max(params, Array(type_info[:max_size])) if type_info[:max_size]
|
222
|
+
params = check_and_replace_max(params, Array(type_info[:max_size]), type) if type_info[:max_size]
|
222
223
|
else
|
223
224
|
#source data type has no parameter. use default parameters.
|
224
225
|
raise "No default pramameters for type:`#{column[:type]}`" unless type_info[:default_params]
|
@@ -272,7 +273,7 @@ EOS
|
|
272
273
|
raise "default value of YEAR type must be 2 or 4-digit, value:'#{default_value}'"
|
273
274
|
end
|
274
275
|
elsif flydata_type.start_with?('money')
|
275
|
-
default_value =
|
276
|
+
default_value = ValueConv.strip_currency_format(remove_single_quote(default_value))
|
276
277
|
end
|
277
278
|
|
278
279
|
case redshift_type
|
@@ -413,11 +414,29 @@ EOS
|
|
413
414
|
text.gsub(/(['\\])/, "\\\\\\1")
|
414
415
|
end
|
415
416
|
|
416
|
-
def self.check_and_replace_max(params, max_size_a)
|
417
|
+
def self.check_and_replace_max(params, max_size_a, flydata_type)
|
417
418
|
final_params = []
|
418
|
-
|
419
|
-
|
420
|
-
|
419
|
+
case flydata_type
|
420
|
+
when 'numeric', 'numeric unsigned'
|
421
|
+
p = params.split(",")
|
422
|
+
raise "Wrong number of params for #{flydata_type} type." if p.length != max_size_a.length
|
423
|
+
above_decimal = p[0].to_i - p[1].to_i
|
424
|
+
below_decimal = p[1].to_i
|
425
|
+
|
426
|
+
# use max precision as the max number of above-dicimal digits
|
427
|
+
max_above_decimal = max_size_a[0]
|
428
|
+
final_above_decimal = above_decimal > max_above_decimal ? max_above_decimal : above_decimal
|
429
|
+
|
430
|
+
max_below_decimal = max_size_a[0] - final_above_decimal
|
431
|
+
max_below_decimal = max_size_a[1] if max_below_decimal > max_size_a[1]
|
432
|
+
final_below_decimal = below_decimal > max_below_decimal ? max_below_decimal : below_decimal
|
433
|
+
|
434
|
+
final_params << (final_above_decimal + final_below_decimal) << final_below_decimal
|
435
|
+
else
|
436
|
+
params.split(",").each_with_index do |param, i|
|
437
|
+
final_params << (/\d+/.match(param) && max_size_a[i] && param.to_i > max_size_a[i].to_i ?
|
438
|
+
max_size_a[i] : param)
|
439
|
+
end
|
421
440
|
end
|
422
441
|
final_params.join(",")
|
423
442
|
end
|
@@ -506,26 +525,6 @@ EOS
|
|
506
525
|
value # Return the value as is
|
507
526
|
end
|
508
527
|
end
|
509
|
-
|
510
|
-
def self.parse_money(value)
|
511
|
-
# It's impossible to determine a decimal point of a currency sting without
|
512
|
-
# knowing its format. Here, we're making a best effort guess to support
|
513
|
-
# as many currencty formats as we can without knowing the format.
|
514
|
-
value = value.gsub(/[^0-9\.,]/, '') # remove all chars but numbers and possible decimal point chars
|
515
|
-
|
516
|
-
whole_part = value
|
517
|
-
fractional_part = nil
|
518
|
-
if idx = value.rindex(/[\.,]/)
|
519
|
-
if idx == value.size - 3
|
520
|
-
# it's the decimal point with two digit fraction
|
521
|
-
whole_part = value[0...idx]
|
522
|
-
fractional_part = value[-2..-1]
|
523
|
-
end
|
524
|
-
end
|
525
|
-
value = whole_part.gsub(/[^0-9]/, '')
|
526
|
-
value += ".#{fractional_part}" if fractional_part
|
527
|
-
value
|
528
|
-
end
|
529
528
|
end
|
530
529
|
|
531
530
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FlydataCore
|
2
|
+
module TableDef
|
3
|
+
|
4
|
+
# Collection of methods to covert values
|
5
|
+
module ValueConv
|
6
|
+
# currency format string -> decimal string
|
7
|
+
def self.strip_currency_format(value)
|
8
|
+
# It's impossible to determine a decimal point of a currency sting without
|
9
|
+
# knowing its format. Here, we're making a best effort guess to support
|
10
|
+
# as many currency formats as we can without knowing the format.
|
11
|
+
value = value.gsub(/[^0-9\.,]/, '') # remove all chars but numbers and possible decimal point chars
|
12
|
+
|
13
|
+
whole_part = value
|
14
|
+
fractional_part = nil
|
15
|
+
if idx = value.rindex(/[\.,]/)
|
16
|
+
if idx == value.size - 3
|
17
|
+
# it's the decimal point with two digit fraction
|
18
|
+
whole_part = value[0...idx]
|
19
|
+
fractional_part = value[-2..-1]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
value = whole_part.gsub(/[^0-9]/, '')
|
23
|
+
value += ".#{fractional_part}" if fractional_part
|
24
|
+
value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -23,7 +23,7 @@ SELECT
|
|
23
23
|
FROM
|
24
24
|
information_schema.tables
|
25
25
|
WHERE
|
26
|
-
table_schema in (select current_schema)
|
26
|
+
table_schema in ((select current_schema))
|
27
27
|
AND
|
28
28
|
table_name in ('table_1','table_2','table_3');
|
29
29
|
EOT
|
@@ -86,9 +86,9 @@ EOT
|
|
86
86
|
SELECT
|
87
87
|
t.table_name
|
88
88
|
FROM
|
89
|
-
(select * from information_schema.tables where table_schema in (select current_schema) AND table_name in ('table_1','table_2','table_3')) t
|
89
|
+
(select * from information_schema.tables where table_schema in ((select current_schema)) AND table_name in ('table_1','table_2','table_3')) t
|
90
90
|
LEFT OUTER JOIN
|
91
|
-
(select * from information_schema.table_constraints where table_schema in (select current_schema) AND table_name in ('table_1','table_2','table_3')) tc
|
91
|
+
(select * from information_schema.table_constraints where table_schema in ((select current_schema)) AND table_name in ('table_1','table_2','table_3')) tc
|
92
92
|
USING (table_schema, table_name)
|
93
93
|
GROUP BY
|
94
94
|
t.table_schema, t.table_name
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'flydata-core/postgresql/query_helper'
|
3
|
+
|
4
|
+
module FlydataCore
|
5
|
+
module Postgresql
|
6
|
+
|
7
|
+
describe QueryHelper do
|
8
|
+
describe '.schema_as_value' do
|
9
|
+
subject { described_class.schema_as_value(schema) }
|
10
|
+
|
11
|
+
context 'when schema is empty' do
|
12
|
+
let(:schema) { '' }
|
13
|
+
it { is_expected.to eq('(select current_schema)') }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when schema is nil' do
|
17
|
+
let(:schema) { nil }
|
18
|
+
it { is_expected.to eq('(select current_schema)') }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when schema is a text' do
|
22
|
+
let(:schema) { 'test-schema'}
|
23
|
+
it { is_expected.to eq("'test-schema'") }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -10,6 +10,15 @@ module FlydataCore
|
|
10
10
|
describe '#initialize' do
|
11
11
|
subject { subject_object }
|
12
12
|
|
13
|
+
context 'when text is -' do
|
14
|
+
let(:snapshot_text) { '-' }
|
15
|
+
it { expect(subject.xmin).to be_nil }
|
16
|
+
it { expect(subject.xmax).to be_nil }
|
17
|
+
it { expect(subject.xip_list).to be_nil }
|
18
|
+
it { expect(subject.to_s).to eq('-') }
|
19
|
+
it { expect(subject).to be_empty }
|
20
|
+
end
|
21
|
+
|
13
22
|
context 'when xip_list is empty' do
|
14
23
|
let(:snapshot_text) { '10:18:' }
|
15
24
|
it { expect(subject.xmin).to eq(10) }
|
@@ -27,6 +36,20 @@ module FlydataCore
|
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
39
|
+
describe '#empty?' do
|
40
|
+
subject { subject_object.empty? }
|
41
|
+
|
42
|
+
context 'when snapshot_txt is -' do
|
43
|
+
let(:snapshot_text) { '-' }
|
44
|
+
it { is_expected.to be(true) }
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when snapshot_txt is normal value' do
|
48
|
+
let(:snapshot_text) { '10:10:' }
|
49
|
+
it { is_expected.to be(false) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
30
53
|
describe '#<=>' do
|
31
54
|
def new_ss(txt)
|
32
55
|
Snapshot.new(txt)
|
@@ -39,6 +62,8 @@ module FlydataCore
|
|
39
62
|
it { expect(new_ss("10:18:") == new_ss("10:18:10,11,12")).to be(false) }
|
40
63
|
it { expect(new_ss("10:18:10,11,12") == new_ss("10:18:10,11,12")).to be(true) }
|
41
64
|
it { expect(new_ss("10:18:10,11,12") == new_ss("10:18:11,12")).to be(false) }
|
65
|
+
it { expect(new_ss("-") == new_ss("-")).to be(true) }
|
66
|
+
it { expect(new_ss("-") == new_ss("10:10:")).to be(false) }
|
42
67
|
|
43
68
|
it { expect(new_ss("10:10:") > new_ss("10:10:")).to be(false) }
|
44
69
|
it { expect(new_ss("10:10:") > new_ss("11:11:")).to be(false) }
|
@@ -456,28 +456,56 @@ EOT
|
|
456
456
|
end
|
457
457
|
|
458
458
|
context 'with decimal column def' do
|
459
|
+
context 'when precision is exactly max allowed' do
|
460
|
+
let(:default_value) { "'4'" }
|
461
|
+
let(:default_value_sql) { default_value }
|
462
|
+
let(:not_null_default_sql) { " DEFAULT '0'" }
|
463
|
+
before do
|
464
|
+
column[:column] = "value"
|
465
|
+
column[:type] = "numeric(38,4)" #34+4 digits
|
466
|
+
end
|
467
|
+
let(:type_sql) { %Q|"value" numeric(38,4)| }
|
468
|
+
|
469
|
+
it_behaves_like *examples
|
470
|
+
end
|
471
|
+
|
459
472
|
context 'when precision exceeds max allowed' do
|
460
473
|
let(:default_value) { "'4'" }
|
461
474
|
let(:default_value_sql) { default_value }
|
462
475
|
let(:not_null_default_sql) { " DEFAULT '0'" }
|
463
476
|
before do
|
464
477
|
column[:column] = "value"
|
465
|
-
column[:type] = "numeric(
|
478
|
+
column[:type] = "numeric(42,37)" #5+37 (precision 42) => 5+33 digits (precision 38)
|
479
|
+
end
|
480
|
+
# Preserve digits over decimal as much as possible,
|
481
|
+
# and truncate scale.
|
482
|
+
let(:type_sql) { %Q|"value" numeric(38,33)| }
|
483
|
+
|
484
|
+
it_behaves_like *examples
|
485
|
+
end
|
486
|
+
|
487
|
+
context 'when both precision and scale exceed max allowed' do #possible in postgresql
|
488
|
+
let(:default_value) { "'4'" }
|
489
|
+
let(:default_value_sql) { default_value }
|
490
|
+
let(:not_null_default_sql) { " DEFAULT '0'" }
|
491
|
+
before do
|
492
|
+
column[:column] = "value"
|
493
|
+
column[:type] = "numeric(1000,44)" #956+44 => 38+0 digits
|
466
494
|
end
|
467
|
-
let(:type_sql) { %Q|"value" numeric(38,
|
495
|
+
let(:type_sql) { %Q|"value" numeric(38,0)| }
|
468
496
|
|
469
497
|
it_behaves_like *examples
|
470
498
|
end
|
471
|
-
|
499
|
+
|
500
|
+
context 'when only scale exceed max allowed' do
|
472
501
|
let(:default_value) { "'4'" }
|
473
502
|
let(:default_value_sql) { default_value }
|
474
503
|
let(:not_null_default_sql) { " DEFAULT '0'" }
|
475
504
|
before do
|
476
505
|
column[:column] = "value"
|
477
|
-
column[:type] = "numeric(
|
506
|
+
column[:type] = "numeric(38,38)" #0+38 => 0+37 digits
|
478
507
|
end
|
479
|
-
|
480
|
-
let(:type_sql) { %Q|"value" numeric(38,37)| }
|
508
|
+
let(:type_sql) { %Q|"value" numeric(37,37)| }
|
481
509
|
|
482
510
|
it_behaves_like *examples
|
483
511
|
end
|
@@ -503,7 +531,7 @@ EOT
|
|
503
531
|
column[:column] = "value"
|
504
532
|
column[:type] = "numeric(65,44) unsigned"
|
505
533
|
end
|
506
|
-
let(:type_sql) {%Q|"value" numeric(38,
|
534
|
+
let(:type_sql) {%Q|"value" numeric(38,17)| }
|
507
535
|
|
508
536
|
it_behaves_like *examples
|
509
537
|
end
|
@@ -1198,6 +1226,30 @@ EOS
|
|
1198
1226
|
end
|
1199
1227
|
end
|
1200
1228
|
end
|
1229
|
+
context 'with moeny type' do
|
1230
|
+
let(:flydata_type) { "money" }
|
1231
|
+
let(:redshift_type) { "money" }
|
1232
|
+
|
1233
|
+
context 'in dollar format' do
|
1234
|
+
let(:default_value) { "'$2,392.40'" }
|
1235
|
+
it { is_expected.to eq "'2392.40'" }
|
1236
|
+
end
|
1237
|
+
|
1238
|
+
context 'in JPY format' do
|
1239
|
+
let(:default_value) { "'JPY2,382,929'" }
|
1240
|
+
it { is_expected.to eq "'2382929'" }
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
context 'in INR format' do
|
1244
|
+
let(:default_value) { "'12,23,382.29'" }
|
1245
|
+
it { is_expected.to eq "'1223382.29'" }
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
context 'in DKK format' do
|
1249
|
+
let(:default_value) { "'10.382,29'" }
|
1250
|
+
it { is_expected.to eq "'10382.29'" }
|
1251
|
+
end
|
1252
|
+
end
|
1201
1253
|
end
|
1202
1254
|
end
|
1203
1255
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module FlydataCore
|
2
|
+
module TableDef
|
3
|
+
|
4
|
+
require 'flydata-core/table_def/value_conv'
|
5
|
+
|
6
|
+
describe ValueConv do
|
7
|
+
describe '.strip_currency_format' do
|
8
|
+
subject { described_class.strip_currency_format(value) }
|
9
|
+
|
10
|
+
context 'in dollar format' do
|
11
|
+
let(:value) { "$2,392.40" }
|
12
|
+
it { is_expected.to eq "2392.40" }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'in JPY format' do
|
16
|
+
let(:value) { "JPY2,382,929" }
|
17
|
+
it { is_expected.to eq "2382929" }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'in INR format' do
|
21
|
+
let(:value) { "12,23,382.29" }
|
22
|
+
it { is_expected.to eq "1223382.29" }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'in DKK format' do
|
26
|
+
let(:value) { "10.382,29" }
|
27
|
+
it { is_expected.to eq "10382.29" }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/flydata.gemspec
CHANGED
Binary file
|
@@ -219,7 +219,7 @@ EOS
|
|
219
219
|
if @thread and @thread.alive?
|
220
220
|
$log.info "Requesting stop Kodama"
|
221
221
|
begin
|
222
|
-
@kodama_client.stop_request
|
222
|
+
@kodama_client.stop_request if @kodama_client
|
223
223
|
if wait_till_safe_to_stop
|
224
224
|
@thread.join
|
225
225
|
$log.info "Kodama has stopped successfully"
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'flydata/command/sync'
|
4
|
+
|
5
|
+
# Command class must be in module Flydata::Command
|
6
|
+
module Flydata
|
7
|
+
module Command
|
8
|
+
|
9
|
+
class Psql < Sync
|
10
|
+
def run(*args)
|
11
|
+
de = data_entry
|
12
|
+
cmd = generate_command(de['postgresql_data_entry_preference'], args)
|
13
|
+
return if cmd.to_s.empty?
|
14
|
+
$stderr.puts "command:#{cmd}" if FLYDATA_DEBUG
|
15
|
+
if $stdin.tty?
|
16
|
+
# interactive shell
|
17
|
+
system cmd
|
18
|
+
else
|
19
|
+
# execute queries given to $stdin
|
20
|
+
Open3.popen2e(cmd) do |i, o, wt|
|
21
|
+
$stdin.each_line do |line|
|
22
|
+
i.print line
|
23
|
+
end
|
24
|
+
i.close
|
25
|
+
while line = o.gets
|
26
|
+
print line
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def generate_command(dbconf, args)
|
33
|
+
password = Shellwords.escape(dbconf['password'])
|
34
|
+
database = Shellwords.escape(dbconf['database'])
|
35
|
+
host = Shellwords.escape(dbconf['host'])
|
36
|
+
port = Shellwords.escape(dbconf['port'])
|
37
|
+
username = Shellwords.escape(dbconf['username'])
|
38
|
+
"PGCONNECT_TIMEOUT=5 PGPASSWORD=#{password} psql -d #{database} -h #{host} -p #{port} -U #{username}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def flush; end
|
42
|
+
def reset; end
|
43
|
+
def skip; end
|
44
|
+
def generate_table_ddl; end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -14,7 +14,7 @@ class GenerateSourceDump < Source::GenerateSourceDump
|
|
14
14
|
include PostgresqlComponent
|
15
15
|
|
16
16
|
def run_compatibility_check(dump_dir, backup_dir)
|
17
|
-
%w(host username database
|
17
|
+
%w(host username database).each do |k|
|
18
18
|
if de_prefs[k].to_s.empty?
|
19
19
|
raise "'#{k}' is required. Set the value in the conf file " +
|
20
20
|
"-> #{Flydata::Preference::DataEntryPreference.conf_path(de)}"
|
@@ -34,21 +34,24 @@ class GenerateSourceDump < Source::GenerateSourceDump
|
|
34
34
|
items
|
35
35
|
end
|
36
36
|
|
37
|
-
DUMP_SIZE_QUERY = <<EOS
|
37
|
+
DUMP_SIZE_QUERY = <<EOS
|
38
38
|
SELECT sum(pg_total_relation_size(c.oid)) AS "total_size"
|
39
39
|
FROM pg_class c
|
40
40
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
41
|
-
WHERE nspname =
|
41
|
+
WHERE nspname = %{schema} AND relname in (%{tables})
|
42
42
|
EOS
|
43
|
-
TABLE_PLACEHOLDER_START_NUM = 2 # because $1 is used by table_schema
|
44
43
|
|
45
44
|
def dump_size(tables)
|
46
45
|
cli = FlydataCore::Postgresql::PGClient.new(de_prefs)
|
47
46
|
|
48
|
-
|
47
|
+
base_query = DUMP_SIZE_QUERY % {
|
48
|
+
schema: FlydataCore::Postgresql::QueryHelper.schema_as_value(de_prefs['schema']),
|
49
|
+
tables: '%s' # Use binding parameters for tables
|
50
|
+
}
|
51
|
+
query = FlydataCore::Postgresql::PGQuery.new(base_query,
|
49
52
|
placeholder_size: tables.size,
|
50
|
-
placeholder_start_num:
|
51
|
-
res = cli.query(query,
|
53
|
+
placeholder_start_num: 1)
|
54
|
+
res = cli.query(query, tables)
|
52
55
|
|
53
56
|
res.first['total_size'].to_i
|
54
57
|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'flydata-core/postgresql/pg_client'
|
2
|
+
require 'flydata-core/table_def/postgresql_table_def'
|
3
|
+
require 'flydata-core/table_def/value_conv'
|
2
4
|
|
3
5
|
module Flydata
|
4
6
|
module SourcePostgresql
|
@@ -107,7 +109,6 @@ EOS
|
|
107
109
|
h[k] =
|
108
110
|
case k
|
109
111
|
when "bytea"; %Q['0x' || encode("%<column>s", 'hex') AS "%<column>s"]
|
110
|
-
when "money"; %Q["%<column>s"::numeric]
|
111
112
|
else %Q["%<column>s"]
|
112
113
|
end
|
113
114
|
end
|
@@ -116,6 +117,8 @@ EOS
|
|
116
117
|
h[k] =
|
117
118
|
case k
|
118
119
|
when "bit", "varbit"; -> (v) { v ? '%d' % v.to_i(2) : nil }
|
120
|
+
when "boolean"; -> (v) { FlydataCore::TableDef::PostgresqlTableDef::to_boolean(v) }
|
121
|
+
when "money"; -> (v) { FlydataCore::TableDef::ValueConv.strip_currency_format(v) }
|
119
122
|
else
|
120
123
|
nil
|
121
124
|
end
|
@@ -126,7 +129,11 @@ EOS
|
|
126
129
|
end
|
127
130
|
|
128
131
|
def build_value_overriders(columns, types)
|
129
|
-
columns.each_with_index.inject({})
|
132
|
+
columns.each_with_index.inject({}) do |h, (c, i)|
|
133
|
+
overrider = VALUE_OVERRIDERS[types[i]]
|
134
|
+
h[c] = overrider if overrider
|
135
|
+
h
|
136
|
+
end
|
130
137
|
end
|
131
138
|
end
|
132
139
|
|
@@ -10,6 +10,8 @@ module SourcePostgresql
|
|
10
10
|
# Fetch and keep table meta information
|
11
11
|
#
|
12
12
|
# <table-name(Symbol)>:
|
13
|
+
# table_name: <String> # Table name
|
14
|
+
# table_schema: <String> or nil # Schema name
|
13
15
|
# primary_keys: <Array of String> # Set primary key names. ex: ['group_id', 'category_id']
|
14
16
|
# pk_positions: <Array of Integer> # Set the ordinal position of primary keys. ex: [1, 3]
|
15
17
|
# max_row_size: <Integer> # byte, calculated based on column size
|
@@ -45,7 +47,7 @@ SELECT
|
|
45
47
|
c.numeric_precision_radix,
|
46
48
|
CASE WHEN c.data_type='money' THEN (
|
47
49
|
SELECT CASE WHEN scale IS NULL THEN 0 ELSE scale END
|
48
|
-
FROM (SELECT length(substring(999999::money::char varying, '\.([0-9]+)$')) AS scale) s)
|
50
|
+
FROM (SELECT length(substring('999999'::money::char varying, '\.([0-9]+)$')) AS scale) s)
|
49
51
|
ELSE c.numeric_scale END AS numeric_scale,
|
50
52
|
c.datetime_precision,
|
51
53
|
i.indisprimary AS is_primary
|
@@ -72,11 +74,12 @@ EOT
|
|
72
74
|
DEFAULT_MAX_FETCH_RECORD_SIZE = 50000
|
73
75
|
#DEFAULT_MAX_FETCH_RECORD_SIZE = 8
|
74
76
|
|
75
|
-
def initialize(dbconf, tables, schema = nil)
|
77
|
+
def initialize(dbconf, tables, schema = nil)
|
76
78
|
@dbconf = dbconf
|
77
79
|
@database = dbconf[:dbname] || dbconf[:database] || dbconf['database']
|
78
80
|
@tables = tables
|
79
|
-
@schema = schema || dbconf[:schema] || dbconf['schema']
|
81
|
+
@schema = (schema || dbconf[:schema] || dbconf['schema']).to_s.strip
|
82
|
+
@schema = @schema.empty? ? nil : @schema
|
80
83
|
end
|
81
84
|
|
82
85
|
attr_reader :current_snapshot
|
@@ -145,6 +148,7 @@ EOT
|
|
145
148
|
|
146
149
|
t_meta.merge!(
|
147
150
|
table_name: table_name.to_s,
|
151
|
+
table_schema: @schema,
|
148
152
|
primary_keys: primary_keys,
|
149
153
|
pk_positions: pk_positions,
|
150
154
|
#max_row_size: max_row_size, #TODO: calculation
|
@@ -17,7 +17,7 @@ module Fluent
|
|
17
17
|
tables_append_only test_table_3
|
18
18
|
position_file #{TEST_POSITION_FILE}
|
19
19
|
host localhost
|
20
|
-
port
|
20
|
+
port 5433
|
21
21
|
username test_admin
|
22
22
|
password test_password
|
23
23
|
database test_db
|
@@ -50,6 +50,7 @@ EOT
|
|
50
50
|
'tables' => 'test_table,test_table_1,test_table_2',
|
51
51
|
'tables_append_only' => 'test_table_3',
|
52
52
|
'host' => 'localhost',
|
53
|
+
'port' => 5433,
|
53
54
|
'username' => 'test_admin',
|
54
55
|
'password' => 'test_password',
|
55
56
|
'schema' => 'test_schema',
|
@@ -71,10 +71,11 @@ EOS
|
|
71
71
|
|
72
72
|
context 'when columns includes a money type' do
|
73
73
|
let(:value_data_type) { 'money(19,2)' }
|
74
|
-
it 'returns money values as
|
74
|
+
it 'returns money values as is' do
|
75
75
|
is_expected.to eq(<<EOS)
|
76
|
-
SELECT "id", "value"
|
76
|
+
SELECT "id", "value" FROM "public"."test_table" WHERE txid_visible_in_snapshot(xmin::TEXT::BIGINT, '0002:0002:') AND NOT txid_visible_in_snapshot(xmin::TEXT::BIGINT, '0001:0001:') AND ("id" > $1) ORDER BY "id" LIMIT 100;
|
77
77
|
EOS
|
78
|
+
expect(subject.value_overriders).to eq({"value" => DiffQueryGenerator::VALUE_OVERRIDERS['money']})
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
@@ -100,6 +101,17 @@ EOS
|
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
104
|
+
context 'when columns includes a boolean type' do
|
105
|
+
let(:value_data_type) { 'boolean' }
|
106
|
+
it 'returns a query with an overrider proc for boolean' do
|
107
|
+
result = subject
|
108
|
+
expect(result).to eq(<<EOS)
|
109
|
+
SELECT "id", "value" FROM "public"."test_table" WHERE txid_visible_in_snapshot(xmin::TEXT::BIGINT, '0002:0002:') AND NOT txid_visible_in_snapshot(xmin::TEXT::BIGINT, '0001:0001:') AND ("id" > $1) ORDER BY "id" LIMIT 100;
|
110
|
+
EOS
|
111
|
+
expect(result.value_overriders).to eq({"value" => DiffQueryGenerator::VALUE_OVERRIDERS['boolean']})
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
103
115
|
context 'when from_sid is not given' do
|
104
116
|
let(:from_sid) { nil }
|
105
117
|
it { is_expected.to eq(<<EOS)
|
@@ -131,9 +143,17 @@ EOS
|
|
131
143
|
subject { DiffQueryGenerator::VALUE_OVERRIDERS[type].call(value) }
|
132
144
|
|
133
145
|
context 'when type is bit' do
|
134
|
-
|
135
|
-
|
136
|
-
|
146
|
+
context 'when value is not nil' do
|
147
|
+
let(:type) { 'bit' }
|
148
|
+
let(:value) { '0110000010' }
|
149
|
+
it { is_expected.to eq '386' }
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when value is nil' do
|
153
|
+
let(:type) { 'bit' }
|
154
|
+
let(:value) { nil }
|
155
|
+
it { is_expected.to eq nil }
|
156
|
+
end
|
137
157
|
end
|
138
158
|
|
139
159
|
context 'when type is varbit' do
|
@@ -143,10 +163,24 @@ EOS
|
|
143
163
|
it { is_expected.to eq "18446744073709551613" }
|
144
164
|
end
|
145
165
|
|
146
|
-
context 'when
|
147
|
-
|
148
|
-
|
149
|
-
|
166
|
+
context 'when type is boolean' do
|
167
|
+
context 'when value is true' do
|
168
|
+
let(:type) { 'boolean' }
|
169
|
+
let(:value) { 't' }
|
170
|
+
it { is_expected.to eq true }
|
171
|
+
end
|
172
|
+
|
173
|
+
context 'when value is false' do
|
174
|
+
let(:type) { 'boolean' }
|
175
|
+
let(:value) { 'f' }
|
176
|
+
it { is_expected.to eq false }
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'when value is nil' do
|
180
|
+
let(:type) { 'boolean' }
|
181
|
+
let(:value) { nil }
|
182
|
+
it { is_expected.to eq nil }
|
183
|
+
end
|
150
184
|
end
|
151
185
|
end
|
152
186
|
|
@@ -201,8 +235,8 @@ EOS
|
|
201
235
|
|
202
236
|
context 'with a money column' do
|
203
237
|
let(:value_data_type) { 'money' }
|
204
|
-
it 'generates a list which outputs money values as
|
205
|
-
is_expected.to eq %Q["id", "value"
|
238
|
+
it 'generates a list which outputs money values as is' do
|
239
|
+
is_expected.to eq %Q["id", "value"]
|
206
240
|
end
|
207
241
|
end
|
208
242
|
end
|
@@ -72,6 +72,25 @@ module Flydata::SourcePostgresql
|
|
72
72
|
expect(subject[:table_a][:table_def]).to be_kind_of(FlydataCore::TableDef::Base)
|
73
73
|
end
|
74
74
|
end
|
75
|
+
|
76
|
+
context 'when schema is empty' do
|
77
|
+
let(:input_cli) { nil }
|
78
|
+
let(:schema) { nil }
|
79
|
+
|
80
|
+
before do
|
81
|
+
dbconf.delete(:schema)
|
82
|
+
dbconf.delete('schema')
|
83
|
+
allow(conn).to receive(:close)
|
84
|
+
end
|
85
|
+
it 'uses a current schema on query' do
|
86
|
+
expect(conn).to receive(:query) do |query|
|
87
|
+
expect(query).to match(/AND c.table_schema IN \(select current_schema\)/)
|
88
|
+
raw_columns
|
89
|
+
end
|
90
|
+
expect(conn).to receive(:query).with('SELECT txid_current_snapshot();').and_return(current_snapshots)
|
91
|
+
subject
|
92
|
+
end
|
93
|
+
end
|
75
94
|
end
|
76
95
|
end
|
77
96
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Custom configuration for flydata client
|
2
|
+
# This file is yaml format. http://www.yaml.org/
|
3
|
+
# Please remove '#' to enable custom option settings.
|
4
|
+
postgresql_data_entry_preference:
|
5
|
+
#host: localhost
|
6
|
+
#port: 5432
|
7
|
+
#username: root
|
8
|
+
#password: abcd
|
9
|
+
#database: dev
|
10
|
+
#schema: public
|
11
|
+
#tables: users,country,rows
|
12
|
+
#tables_append_only: employees
|
13
|
+
#dump_dir: /mnt/dump
|
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.1
|
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-04-
|
15
|
+
date: 2016-04-05 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: rest-client
|
@@ -547,6 +547,7 @@ files:
|
|
547
547
|
- flydata-core/lib/flydata-core/postgresql/compatibility_checker.rb
|
548
548
|
- flydata-core/lib/flydata-core/postgresql/config.rb
|
549
549
|
- flydata-core/lib/flydata-core/postgresql/pg_client.rb
|
550
|
+
- flydata-core/lib/flydata-core/postgresql/query_helper.rb
|
550
551
|
- flydata-core/lib/flydata-core/postgresql/snapshot.rb
|
551
552
|
- flydata-core/lib/flydata-core/postgresql/source_pos.rb
|
552
553
|
- flydata-core/lib/flydata-core/query_job.rb
|
@@ -560,6 +561,7 @@ files:
|
|
560
561
|
- flydata-core/lib/flydata-core/table_def/postgresql_table_def.rb
|
561
562
|
- flydata-core/lib/flydata-core/table_def/redshift_table_def.rb
|
562
563
|
- flydata-core/lib/flydata-core/table_def/sync_redshift_table_def.rb
|
564
|
+
- flydata-core/lib/flydata-core/table_def/value_conv.rb
|
563
565
|
- flydata-core/lib/flydata-core/thread_context.rb
|
564
566
|
- flydata-core/lib/flydata-core/wrapper_forwardable.rb
|
565
567
|
- flydata-core/spec/config/user_maintenance_spec.rb
|
@@ -579,6 +581,7 @@ files:
|
|
579
581
|
- flydata-core/spec/postgresql/compatibility_checker_spec.rb
|
580
582
|
- flydata-core/spec/postgresql/config_spec.rb
|
581
583
|
- flydata-core/spec/postgresql/pg_client_spec.rb
|
584
|
+
- flydata-core/spec/postgresql/query_helper_spec.rb
|
582
585
|
- flydata-core/spec/postgresql/snapshot_spec.rb
|
583
586
|
- flydata-core/spec/postgresql/source_pos_spec.rb
|
584
587
|
- flydata-core/spec/redshift/string_spec.rb
|
@@ -609,6 +612,7 @@ files:
|
|
609
612
|
- flydata-core/spec/table_def/postgresql_table_def_spec.rb
|
610
613
|
- flydata-core/spec/table_def/redshift_table_def_spec.rb
|
611
614
|
- flydata-core/spec/table_def/sync_redshift_table_def_spec.rb
|
615
|
+
- flydata-core/spec/table_def/value_conv_spec.rb
|
612
616
|
- flydata-core/spec/wrapper_forwardable_spec.rb
|
613
617
|
- flydata.gemspec
|
614
618
|
- lib/fly_data_model.rb
|
@@ -735,6 +739,7 @@ files:
|
|
735
739
|
- lib/flydata/source_mysql/sync_generate_table_ddl.rb
|
736
740
|
- lib/flydata/source_mysql/table_ddl.rb
|
737
741
|
- lib/flydata/source_mysql/table_meta.rb
|
742
|
+
- lib/flydata/source_postgresql/command/psql.rb
|
738
743
|
- lib/flydata/source_postgresql/data_entry.rb
|
739
744
|
- lib/flydata/source_postgresql/generate_source_dump.rb
|
740
745
|
- lib/flydata/source_postgresql/parse_dump_and_send.rb
|
@@ -843,6 +848,7 @@ files:
|
|
843
848
|
- spec/spec_helper.rb
|
844
849
|
- test-suite.sh
|
845
850
|
- tmpl/redshift_mysql_data_entry.conf.tmpl
|
851
|
+
- tmpl/redshift_postgresql_data_entry.conf.tmpl
|
846
852
|
homepage: http://flydata.com/
|
847
853
|
licenses:
|
848
854
|
- All right reserved.
|