myreplicator 1.0.6 → 1.1.0
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.
- data/app/assets/javascripts/myreplicator/select2.js +2685 -0
- data/app/assets/stylesheets/myreplicator/select2-spinner.gif +0 -0
- data/app/assets/stylesheets/myreplicator/select2.css +612 -0
- data/app/assets/stylesheets/myreplicator/select2.png +0 -0
- data/app/models/myreplicator/export.rb +25 -7
- data/app/models/myreplicator/vertica_export.rb +5 -0
- data/app/views/myreplicator/exports/_form.html.erb +48 -27
- data/app/views/myreplicator/exports/index.html.erb +4 -4
- data/db/migrate/20130213211927_create_myreplicator_vertica_exports.rb +22 -0
- data/db/migrate/20130213211927_create_myreplicator_vertica_exports.rb~ +8 -0
- data/lib/exporter/export_metadata.rb +7 -1
- data/lib/exporter/mysql_exporter.rb +103 -29
- data/lib/exporter/sql_commands.rb +8 -9
- data/lib/exporter.rb +1 -0
- data/lib/loader/loader.rb +32 -12
- data/lib/loader/vertica/source_db.rb +30 -0
- data/lib/loader/vertica/source_db.rb~ +30 -0
- data/lib/loader/vertica/types.rb +44 -0
- data/lib/loader/vertica/vertica_loader.rb +235 -0
- data/lib/loader/vertica/vertica_loader.rb~ +175 -0
- data/lib/loader/vertica/vertica_sql.rb +59 -0
- data/lib/loader/vertica/vertica_sql.rb~ +60 -0
- data/lib/loader/vertica.rb +1 -0
- data/lib/myreplicator/version.rb +1 -1
- data/lib/transporter/transporter.rb +11 -1
- data/test/dummy/app/models/vertica_db.rb +7 -0
- data/test/dummy/config/database.yml +7 -0
- data/test/dummy/config/database.yml~ +2 -2
- data/test/dummy/config/myreplicator.yml +5 -0
- data/test/dummy/config/myreplicator.yml~ +0 -2
- data/test/dummy/log/development.log +1664 -9510
- data/test/dummy/tmp/cache/assets/CD5/B90/sprockets%2Fc999d13a6a21113981c0d820e8043bdf +0 -0
- data/test/dummy/tmp/cache/assets/CD7/030/sprockets%2F9ba4859590582b8b72a650b2b00b6cd2 +0 -0
- data/test/dummy/tmp/cache/assets/CE5/670/sprockets%2Fe9e4122f1706626a21da6f8457f088ce +0 -0
- data/test/dummy/tmp/cache/assets/D06/5D0/sprockets%2F91850a20c0ddfa3d8814ca91870fb715 +0 -0
- data/test/dummy/tmp/cache/assets/D14/3A0/sprockets%2Fe59a60053fada52e8185281b4ee887a5 +0 -0
- data/test/dummy/tmp/cache/assets/D7C/E30/sprockets%2F0ba91e21bddfc7e1de102b22183e1e11 +0 -0
- data/test/dummy/tmp/cache/assets/D8B/B60/sprockets%2Faa32227c440a378ccd21218eefeb80bf +0 -0
- data/test/dummy/tmp/cache/assets/DA7/E50/sprockets%2F47bf4f2b4afeac775e6d572a83343fb8 +0 -0
- data/test/dummy/tmp/cache/assets/DA8/910/sprockets%2Fab5775c4a837bd4d97ac394d473cda9b +0 -0
- data/test/dummy/tmp/cache/assets/DAA/060/sprockets%2Facc0d22b9d28123cc1c84d0db630d0ba +0 -0
- data/test/dummy/tmp/cache/assets/DF8/5D0/sprockets%2Fb815ed34d61cfed96222daa3bfd1d84d +0 -0
- data/test/dummy/tmp/cache/assets/E1C/AC0/sprockets%2Faff544a3a34eb7dab7d46b0cb2cd7b70 +0 -0
- data/test/dummy/tmp/cache/assets/E2E/1F0/sprockets%2Fa24e3d7bc5ae4d40adf6f1b8fe94e7c3 +0 -0
- data/test/fixtures/myreplicator/vertica_exports.yml +11 -0
- data/test/unit/myreplicator/vertica_export_test.rb +9 -0
- metadata +43 -13
- data/test/dummy/tmp/myreplicator/okl_test_batchy_batches_1358547945.tsv.gz +0 -0
- data/test/dummy/tmp/myreplicator/okl_test_batchy_batches_1358547945.tsv.json +0 -1
@@ -1,6 +1,6 @@
|
|
1
1
|
<%
|
2
2
|
#rather than yaml arrays of the drop downs
|
3
|
-
export_to = ["destination_db","
|
3
|
+
export_to = ["destination_db","backup","vertica"]
|
4
4
|
export_type = ["incremental","fulldump"]
|
5
5
|
%>
|
6
6
|
<%= form_for(@export) do |f| %>
|
@@ -16,6 +16,18 @@ export_type = ["incremental","fulldump"]
|
|
16
16
|
</div>
|
17
17
|
<% end %>
|
18
18
|
<div class="form-section">
|
19
|
+
<label>Export to</label>
|
20
|
+
<select name="export[export_to]" id="export_to" class="chosen" data-placeholder="Select export destination">
|
21
|
+
<% export_to.each do |val| %>
|
22
|
+
<option value="<%= val %>" <% if @export.export_to == val %>SELECTED<% end %>><%= val %></option>
|
23
|
+
<% end %>
|
24
|
+
</select>
|
25
|
+
<label>Export type</label>
|
26
|
+
<select name="export[export_type]" id="export_type" class="chosen" data-placeholder="Select your export type">
|
27
|
+
<% export_type.each do |val| %>
|
28
|
+
<option value="<%= val %>" <% if @export.export_type == val %>SELECTED<% end %>><%= val %></option>
|
29
|
+
<% end %>
|
30
|
+
</select>
|
19
31
|
<label>Source Schema</label>
|
20
32
|
<%= f.select :source_schema, @dbs %>
|
21
33
|
<label>Destination Schema</label>
|
@@ -28,20 +40,8 @@ export_type = ["incremental","fulldump"]
|
|
28
40
|
<%= f.text_field :incremental_column_type %>
|
29
41
|
<label>Maximum Incremental Value</label>
|
30
42
|
<%= f.text_field :max_incremental_value %>
|
31
|
-
<label>
|
43
|
+
<label>Store a copy in</label>
|
32
44
|
<%= f.text_field :s3_path %>
|
33
|
-
<label>Export to</label>
|
34
|
-
<select name="export[export_to]" id="export_to" class="chosen" data-placeholder="Select export destination">
|
35
|
-
<% export_to.each do |val| %>
|
36
|
-
<option value="<%= val %>" <% if @export.export_to == val %>SELECTED<% end %>><%= val %></option>
|
37
|
-
<% end %>
|
38
|
-
</select>
|
39
|
-
<label>Export type</label>
|
40
|
-
<select name="export[export_type]" id="export_type" class="chosen" data-placeholder="Select your export type">
|
41
|
-
<% export_type.each do |val| %>
|
42
|
-
<option value="<%= val %>" <% if @export.export_type == val %>SELECTED<% end %>><%= val %></option>
|
43
|
-
<% end %>
|
44
|
-
</select>
|
45
45
|
<label>Active</label>
|
46
46
|
<select name="export[active]" id="active" class="chosen">
|
47
47
|
<option value="true" <% if @export.active == true %>SELECTED<% end %>>true</option>
|
@@ -124,8 +124,7 @@ export_type = ["incremental","fulldump"]
|
|
124
124
|
<%= link_to content_tag(:span, 'cancel'), exports_path, :class => "btn left action cancel" %>
|
125
125
|
</div>
|
126
126
|
<% end %>
|
127
|
-
|
128
|
-
<%= javascript_include_tag "myreplicator/cronwtf.min" %>
|
127
|
+
|
129
128
|
<script>
|
130
129
|
var dbs = {
|
131
130
|
<% @tables.each do |key,values| %>
|
@@ -138,13 +137,28 @@ var dbs = {
|
|
138
137
|
}
|
139
138
|
$(function(){
|
140
139
|
CronUI.translate();
|
141
|
-
$(".chosen").
|
142
|
-
$("#export_destination_schema
|
140
|
+
$(".chosen").select2();
|
141
|
+
var $destination = $("#export_destination_schema").clone();
|
142
|
+
var $table_name = $("#export_table_name").clone()
|
143
|
+
$("#export_destination_schema").select2();
|
144
|
+
$("#export_table_name").select2();
|
143
145
|
$(".cron").chosen().change(function(){CronUI.translate()});
|
144
|
-
$("#export_source_schema").
|
146
|
+
$("#export_source_schema").select2().change(function(){
|
145
147
|
exportSchemaSelect($(this).val())
|
146
148
|
});
|
147
149
|
exportSchemaSelect($("#export_source_schema").val());
|
150
|
+
|
151
|
+
$("#export_to").change(function(){
|
152
|
+
var exp = $(this).val();
|
153
|
+
if(exp == 'vertica'){
|
154
|
+
$("#export_destination_schema").select2("destroy").before('<input type="text" id="export_destination_schema" name="export[destination_schema]"/>').remove();
|
155
|
+
}else{
|
156
|
+
if($("#s2id_export_destination_schema").length < 1){
|
157
|
+
$("#export_destination_schema").before($destination).remove();
|
158
|
+
$("#export_destination_schema").select2();
|
159
|
+
}
|
160
|
+
}
|
161
|
+
})
|
148
162
|
$("#cron-min").slider({
|
149
163
|
min: 1,
|
150
164
|
max: 59,
|
@@ -218,18 +232,25 @@ function editInit(){
|
|
218
232
|
}
|
219
233
|
}
|
220
234
|
CronUI.translate();
|
221
|
-
|
235
|
+
<% if @export.export_to != 'vertica' %>
|
236
|
+
$("#export_table_name").select2("val","<%= @export.table_name %>")
|
237
|
+
<% else %>
|
238
|
+
$("#export_destination_schema").select2("destroy").before('<input type="text" id="export_destination_schema" name="export[destination_schema]" value="<%= @export.destination_schema %>"/>').remove();
|
239
|
+
<% end %>
|
222
240
|
}
|
223
241
|
|
224
242
|
function exportSchemaSelect(val){
|
225
243
|
var target = $("#export_table_name");
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
options
|
244
|
+
if(target.hasClass("select2-offscreen")){
|
245
|
+
target.select2("destroy")
|
246
|
+
var tables = dbs[val];
|
247
|
+
var l = tables.length;
|
248
|
+
var options = "";
|
249
|
+
for(i=0;i<l;i++){
|
250
|
+
options += "<option value='"+tables[i]+"'>"+tables[i]+"</option>";
|
251
|
+
}
|
252
|
+
target.val('').find("option").remove()
|
253
|
+
target.append(options).select2();
|
231
254
|
}
|
232
|
-
target.val('').find("option").remove().trigger("liszt:updated");
|
233
|
-
target.append(options).trigger("liszt:updated");
|
234
255
|
}
|
235
256
|
</script>
|
@@ -8,14 +8,14 @@
|
|
8
8
|
<table class="data-grid">
|
9
9
|
<thead>
|
10
10
|
<tr>
|
11
|
+
<th><%= sortable "export_type" %></th>
|
12
|
+
<th><%= sortable "export_to", "Export Desitination" %></th>
|
11
13
|
<th colspan="2"><%= sortable "source_schema" %></th>
|
12
14
|
<th><%= sortable "destination_schema" %></th>
|
13
15
|
<th><%= sortable "table_name" %></th>
|
14
16
|
<th><%= sortable "incremental_column" %></th>
|
15
17
|
<th><%= sortable "incremental_column_type" %></th>
|
16
18
|
<th><%= sortable "max_incremental_value" %></th>
|
17
|
-
<th><%= sortable "export_to", "Export Desitination" %></th>
|
18
|
-
<th><%= sortable "export_type" %></th>
|
19
19
|
<th><%= sortable "s3_path" %></th>
|
20
20
|
<th><%= sortable "cron" %></th>
|
21
21
|
<th class="center">Actions</th>
|
@@ -24,6 +24,8 @@
|
|
24
24
|
<tbody>
|
25
25
|
<% @exports.each do |export| %>
|
26
26
|
<tr>
|
27
|
+
<td><%= export.export_type %></td>
|
28
|
+
<td><%= export.export_to %></td>
|
27
29
|
<td class="state"><span class="status <% if export.active %>active<% else %>inactive<% end %>" title="<% if export.active %>Active<% else %>Inactive<% end %>"></span></td>
|
28
30
|
<td class="source"><%= export.source_schema %></td>
|
29
31
|
<td><%= export.destination_schema %></td>
|
@@ -31,8 +33,6 @@
|
|
31
33
|
<td><%= export.incremental_column %></td>
|
32
34
|
<td><%= export.incremental_column_type %></td>
|
33
35
|
<td><%= export.max_incremental_value %></td>
|
34
|
-
<td><%= export.export_to %></td>
|
35
|
-
<td><%= export.export_type %></td>
|
36
36
|
<td><%= export.s3_path %></td>
|
37
37
|
<td><span class="cron" data-cron="<%= export.cron %>" title=""><%= export.cron %></span></td>
|
38
38
|
<td>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateMyreplicatorVerticaExports < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :myreplicator_vertica_exports do |t|
|
4
|
+
t.string :database
|
5
|
+
t.string :schema
|
6
|
+
t.string :table_name
|
7
|
+
t.string :file_path
|
8
|
+
t.string :file_format
|
9
|
+
t.string :delimiter
|
10
|
+
t.string :field_enclosed_by
|
11
|
+
t.string :line_terminated_by
|
12
|
+
t.string :cron
|
13
|
+
t.string :state, :default => "new"
|
14
|
+
t.text :error
|
15
|
+
t.boolean :active, :default => true
|
16
|
+
t.integer :exporter_pid
|
17
|
+
t.datetime :export_started_at, :default => nil
|
18
|
+
t.datetime :export_finished_at, :default => nil
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -5,6 +5,7 @@ module Myreplicator
|
|
5
5
|
|
6
6
|
attr_accessor(:export_time,
|
7
7
|
:export_finished_at,
|
8
|
+
:export_to,
|
8
9
|
:table,
|
9
10
|
:database,
|
10
11
|
:state,
|
@@ -13,6 +14,7 @@ module Myreplicator
|
|
13
14
|
:incremental_val,
|
14
15
|
:ssh,
|
15
16
|
:export_type,
|
17
|
+
:store_in,
|
16
18
|
:on_duplicate,
|
17
19
|
:filepath,
|
18
20
|
:zipped,
|
@@ -158,7 +160,9 @@ module Myreplicator
|
|
158
160
|
:export_id => @export_id,
|
159
161
|
:filepath => @filepath,
|
160
162
|
:zipped => @zipped,
|
161
|
-
:export_type => @export_type
|
163
|
+
:export_type => @export_type,
|
164
|
+
:export_to => @export_to,
|
165
|
+
:store_in => @store_in
|
162
166
|
}
|
163
167
|
return obj.to_json
|
164
168
|
end
|
@@ -203,6 +207,8 @@ module Myreplicator
|
|
203
207
|
@on_duplicate = options[:on_duplicate] if options[:on_duplicate]
|
204
208
|
@export_type = options[:export_type] if options[:export_type]
|
205
209
|
@zipped = options[:zipped].nil? ? false : options[:zipped]
|
210
|
+
@store_in = options[:store_in] if options[:store_in]
|
211
|
+
@export_to = options[:export_to] if options[:export_to]
|
206
212
|
@ssh = nil
|
207
213
|
|
208
214
|
@success_callbacks = []
|
@@ -15,19 +15,19 @@ module Myreplicator
|
|
15
15
|
|
16
16
|
ExportMetadata.record(:table => @export_obj.table_name,
|
17
17
|
:database => @export_obj.source_schema,
|
18
|
+
:export_to => load_to,
|
18
19
|
:export_id => @export_obj.id,
|
19
20
|
:filepath => filepath,
|
21
|
+
:store_in => @export_obj.s3_path,
|
20
22
|
:incremental_col => @export_obj.incremental_column) do |metadata|
|
21
23
|
|
22
24
|
prepare metadata
|
23
25
|
|
24
|
-
|
25
|
-
when :new
|
26
|
+
if @export_obj.export_type? == :new && load_to == "mysql"
|
26
27
|
on_failure_state_trans(metadata, "new") # If failed, go back to new
|
27
28
|
on_export_success(metadata)
|
28
29
|
initial_export metadata
|
29
|
-
|
30
|
-
when :incremental
|
30
|
+
elsif @export_obj.export_type? == :incremental or load_to == "vertica"
|
31
31
|
on_failure_state_trans(metadata, "failed") # Set state trans on failure
|
32
32
|
on_export_success(metadata)
|
33
33
|
incremental_export metadata
|
@@ -35,7 +35,15 @@ module Myreplicator
|
|
35
35
|
|
36
36
|
end # metadata
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
|
+
def load_to
|
40
|
+
if @export_obj.export_to == "vertica"
|
41
|
+
return "vertica"
|
42
|
+
else
|
43
|
+
return "mysql"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
39
47
|
##
|
40
48
|
# Setups SSH connection to remote host
|
41
49
|
##
|
@@ -65,12 +73,10 @@ module Myreplicator
|
|
65
73
|
metadata.export_type = "initial"
|
66
74
|
max_value = @export_obj.max_value if @export_obj.incremental_export?
|
67
75
|
cmd = initial_mysqldump_cmd
|
68
|
-
|
69
76
|
exporting_state_trans # mark exporting
|
70
77
|
|
71
78
|
puts "Exporting..."
|
72
79
|
result = execute_export(cmd, metadata)
|
73
|
-
|
74
80
|
check_result(result, 0)
|
75
81
|
|
76
82
|
@export_obj.update_max_val(max_value) if @export_obj.incremental_export?
|
@@ -78,10 +84,19 @@ module Myreplicator
|
|
78
84
|
|
79
85
|
def initial_mysqldump_cmd
|
80
86
|
flags = ["create-options", "single-transaction"]
|
81
|
-
cmd =
|
82
|
-
|
83
|
-
|
84
|
-
|
87
|
+
cmd = ""
|
88
|
+
# Mysql - Mysql Export
|
89
|
+
if @export_obj.export_to == "destination_db"
|
90
|
+
cmd = SqlCommands.mysqldump(:db => @export_obj.source_schema,
|
91
|
+
:flags => flags,
|
92
|
+
:filepath => filepath,
|
93
|
+
:table_name => @export_obj.table_name)
|
94
|
+
else # Other destinations
|
95
|
+
cmd = SqlCommands.mysql_export_outfile(:db => @export_obj.source_schema,
|
96
|
+
:filepath => filepath,
|
97
|
+
:table => @export_obj.table_name)
|
98
|
+
end
|
99
|
+
|
85
100
|
return cmd
|
86
101
|
end
|
87
102
|
|
@@ -118,6 +133,7 @@ module Myreplicator
|
|
118
133
|
cmd = SqlCommands.mysql_export(:db => @export_obj.source_schema,
|
119
134
|
:filepath => filepath,
|
120
135
|
:sql => sql)
|
136
|
+
|
121
137
|
return cmd
|
122
138
|
end
|
123
139
|
|
@@ -125,27 +141,85 @@ module Myreplicator
|
|
125
141
|
# Exports table incrementally, similar to incremental_export method
|
126
142
|
# Dumps file in tmp directory specified in myreplicator.yml
|
127
143
|
# Note that directory needs 777 permissions for mysql to be able to export the file
|
128
|
-
# Uses
|
144
|
+
# Uses \\0 as the delimiter and new line for lines
|
129
145
|
##
|
130
146
|
|
131
147
|
def incremental_export_into_outfile metadata
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
148
|
+
unless @export_obj.is_running?
|
149
|
+
max_value = @export_obj.max_value
|
150
|
+
metadata.export_type = "incremental_outfile"
|
151
|
+
@export_obj.update_max_val if @export_obj.max_incremental_value.blank?
|
152
|
+
|
153
|
+
options = {
|
154
|
+
:db => @export_obj.source_schema,
|
155
|
+
:table => @export_obj.table_name,
|
156
|
+
:filepath => filepath,
|
157
|
+
:destination_schema => @export_obj.destination_schema}
|
158
|
+
|
159
|
+
unless schema_changed?(options)[:changed]
|
160
|
+
options[:incremental_col] = @export_obj.incremental_column
|
161
|
+
options[:incremental_col_type] = @export_obj.incremental_column_type
|
162
|
+
options[:incremental_val] = @export_obj.max_incremental_value
|
163
|
+
end
|
164
|
+
|
165
|
+
cmd = SqlCommands.mysql_export_outfile(options)
|
166
|
+
exporting_state_trans
|
167
|
+
puts "Exporting..."
|
168
|
+
result = execute_export(cmd, metadata)
|
169
|
+
check_result(result, 0)
|
170
|
+
metadata.incremental_val = max_value # store max val in metadata
|
171
|
+
@export_obj.update_max_val(max_value) # update max value if export was successful
|
172
|
+
end
|
173
|
+
return false
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.compare_schemas vertica_schema, mysql_schema
|
177
|
+
if vertica_schema.size != mysql_schema.size
|
178
|
+
return {:changed => true, :mysql_schema => mysql_schema, :vertica_schema => vertica_schema,:new => false}
|
179
|
+
else
|
180
|
+
index = 0
|
181
|
+
while index < vertica_schema.size
|
182
|
+
# puts vertica_schema.rows[index][:column_name] + " " + mysql_schema[index]["column_name"]
|
183
|
+
# check for column name
|
184
|
+
if vertica_schema.rows[index][:column_name] != mysql_schema[index]["column_name"]
|
185
|
+
return true
|
186
|
+
end
|
187
|
+
|
188
|
+
# puts vertica_schema.rows[index][:data_type] + " " + VerticaTypes.convert(mysql_schema[index]["data_type"],mysql_schema[index]["column_type"])
|
189
|
+
# check for column's data type
|
190
|
+
if (vertica_schema.rows[index][:data_type] != VerticaTypes.convert(mysql_schema[index]["data_type"],mysql_schema[index]["column_type"]) and vertica_schema.rows[index][:data_type] != "timestamp")
|
191
|
+
return true
|
192
|
+
end
|
193
|
+
# and others ?? (PRIMARY, DEFAULT NULL, etc.)
|
194
|
+
index += 1
|
195
|
+
end
|
196
|
+
end
|
197
|
+
return false
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.schema_changed? options
|
201
|
+
puts options
|
202
|
+
mysql_schema = Loader.mysql_table_definition(options)
|
203
|
+
vertica_schema = VerticaLoader.destination_table_vertica(options)
|
204
|
+
|
205
|
+
# empty result set from vertica means table does not exist
|
206
|
+
unless vertica_schema.size > 0
|
207
|
+
return {:changed => true, :mysql_schema => mysql_schema, :new => true}
|
208
|
+
end
|
209
|
+
|
210
|
+
# compare two schemas
|
211
|
+
mysql_schema_simple_form = []
|
212
|
+
mysql_schema.each(:as => :hash) do |row|
|
213
|
+
mysql_schema_simple_form << row
|
214
|
+
end
|
215
|
+
|
216
|
+
mysql_schema_2 = mysql_schema_simple_form
|
217
|
+
if compare_schemas(vertica_schema, mysql_schema_2)
|
218
|
+
result = {:changed => true, :mysql_schema => mysql_schema, :vertica_schema => vertica_schema,:new => false}
|
219
|
+
else
|
220
|
+
result = {:changed => false}
|
221
|
+
end
|
222
|
+
return result
|
149
223
|
end
|
150
224
|
|
151
225
|
##
|
@@ -36,7 +36,7 @@ module Myreplicator
|
|
36
36
|
# cmd += "--tab=#{options[:filepath]} "
|
37
37
|
# cmd += "--fields-enclosed-by=\'\"\' "
|
38
38
|
# cmd += "--fields-escaped-by=\'\\\\\' "
|
39
|
-
|
39
|
+
|
40
40
|
return cmd
|
41
41
|
end
|
42
42
|
|
@@ -80,16 +80,17 @@ module Myreplicator
|
|
80
80
|
options = args.extract_options!
|
81
81
|
options.reverse_merge! :flags => []
|
82
82
|
db = options[:db]
|
83
|
+
|
83
84
|
# Database host when ssh'ed into the db server
|
84
85
|
|
85
86
|
db_host = "127.0.0.1"
|
86
|
-
|
87
|
+
|
87
88
|
if !ssh_configs(db)["ssh_db_host"].blank?
|
88
89
|
db_host = ssh_configs(db)["ssh_db_host"]
|
89
90
|
elsif !db_configs(db)["host"].blank?
|
90
|
-
db_host
|
91
|
+
db_host = db_configs(db)["host"]
|
91
92
|
end
|
92
|
-
|
93
|
+
|
93
94
|
flags = ""
|
94
95
|
|
95
96
|
self.mysql_flags.each_pair do |flag, value|
|
@@ -120,11 +121,11 @@ module Myreplicator
|
|
120
121
|
def self.get_outfile_sql options
|
121
122
|
sql = "SELECT * INTO OUTFILE '#{options[:filepath]}' "
|
122
123
|
|
123
|
-
sql += " FIELDS TERMINATED BY '
|
124
|
+
sql += " FIELDS TERMINATED BY '\\0' OPTIONALLY ENCLOSED BY '\\\"' LINES TERMINATED BY '\\n'"
|
124
125
|
|
125
126
|
sql += "FROM #{options[:db]}.#{options[:table]} "
|
126
127
|
|
127
|
-
if options[:incremental_col] && options[:incremental_val]
|
128
|
+
if options[:incremental_col] && !options[:incremental_val].blank?
|
128
129
|
if options[:incremental_col_type] == "datetime"
|
129
130
|
sql += "WHERE #{options[:incremental_col]} >= '#{options[:incremental_val]}'"
|
130
131
|
else
|
@@ -159,8 +160,6 @@ module Myreplicator
|
|
159
160
|
end
|
160
161
|
end
|
161
162
|
|
162
|
-
# BOB : You always build the host,password,username part of the command
|
163
|
-
# Seems like this should be in a function somewhere
|
164
163
|
cmd = Myreplicator.mysql
|
165
164
|
cmd += "#{flags} -u#{db_configs(db)["username"]} -p#{db_configs(db)["password"]} "
|
166
165
|
cmd += "-h#{db_host} " if db_configs(db)["host"].blank?
|
@@ -189,7 +188,7 @@ module Myreplicator
|
|
189
188
|
options = args.extract_options!
|
190
189
|
sql = "SELECT * FROM #{options[:db]}.#{options[:table]} "
|
191
190
|
|
192
|
-
if options[:incremental_col] && options[:incremental_val]
|
191
|
+
if options[:incremental_col] && !options[:incremental_val].blank?
|
193
192
|
if options[:incremental_col_type] == "datetime"
|
194
193
|
sql += "WHERE #{options[:incremental_col]} >= '#{options[:incremental_val]}'"
|
195
194
|
else
|
data/lib/exporter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
1
|
Dir["#{File.expand_path(File.dirname(__FILE__))}/exporter/*.rb"].each { | f | require File.expand_path(f) }
|
2
2
|
Dir["#{File.expand_path(File.dirname(__FILE__))}/transporter/*.rb"].each { | f | require File.expand_path(f) }
|
3
3
|
Dir["#{File.expand_path(File.dirname(__FILE__))}/loader/*.rb"].each { | f | require File.expand_path(f) }
|
4
|
+
Dir["#{File.expand_path(File.dirname(__FILE__))}/loader/vertica/*.rb"].each { | f | require File.expand_path(f) }
|
data/lib/loader/loader.rb
CHANGED
@@ -177,24 +177,31 @@ module Myreplicator
|
|
177
177
|
metadata.zipped = false
|
178
178
|
|
179
179
|
options = {:table_name => exp.table_name, :db => exp.destination_schema,
|
180
|
-
:filepath => metadata.destination_filepath(tmp_dir)}
|
180
|
+
:filepath => metadata.destination_filepath(tmp_dir), :source_schema => exp.source_schema}
|
181
181
|
|
182
182
|
if metadata.export_type == "incremental_outfile"
|
183
|
-
options[:fields_terminated_by] = "
|
183
|
+
options[:fields_terminated_by] = "\\0"
|
184
184
|
options[:lines_terminated_by] = "\\n"
|
185
185
|
end
|
186
186
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
187
|
+
case metadata.export_to
|
188
|
+
when "vertica"
|
189
|
+
options = {:table_name => exp.table_name, :db => ActiveRecord::Base.configurations["vertica"]["database"],
|
190
|
+
:filepath => metadata.destination_filepath(tmp_dir), :source_schema => exp.source_schema, :export_id => metadata.export_id}
|
191
|
+
options[:destination_schema] = exp.destination_schema
|
192
|
+
Kernel.p "===== LOAD TO VERTICA ====="
|
193
|
+
Kernel.p options
|
194
|
+
Myreplicator::VerticaLoader.load options
|
195
|
+
when "mysql"
|
196
|
+
cmd = ImportSql.load_data_infile(options)
|
197
|
+
puts cmd
|
198
|
+
result = `#{cmd}` # execute
|
199
|
+
unless result.nil?
|
200
|
+
if result.size > 0
|
201
|
+
raise Exceptions::LoaderError.new("Incremental Load #{metadata.filename} Failed!\n#{result}")
|
202
|
+
end
|
196
203
|
end
|
197
|
-
end
|
204
|
+
end #case
|
198
205
|
end
|
199
206
|
|
200
207
|
##
|
@@ -252,5 +259,18 @@ module Myreplicator
|
|
252
259
|
return files
|
253
260
|
end
|
254
261
|
|
262
|
+
def self.mysql_table_definition options
|
263
|
+
Kernel.p options
|
264
|
+
sql = "SELECT table_schema, table_name, column_name, is_nullable, data_type, column_type, column_key "
|
265
|
+
sql += "FROM INFORMATION_SCHEMA.COLUMNS where table_name = '#{options[:table]}' "
|
266
|
+
sql += "and table_schema = '#{options[:source_schema]}';"
|
267
|
+
|
268
|
+
puts sql
|
269
|
+
|
270
|
+
desc = DB.exec_sql(options[:source_schema], sql)
|
271
|
+
puts desc
|
272
|
+
return desc
|
273
|
+
end
|
274
|
+
|
255
275
|
end
|
256
276
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Myreplicator
|
2
|
+
class DB < ActiveRecord::Base
|
3
|
+
|
4
|
+
def self.connect db
|
5
|
+
establish_connection(ActiveRecord::Base.configurations[db])
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Returns tables as an Array
|
10
|
+
# releases the connection
|
11
|
+
##
|
12
|
+
def self.get_tables(db)
|
13
|
+
tables = []
|
14
|
+
begin
|
15
|
+
self.connect(db)
|
16
|
+
tables = self.connection.tables
|
17
|
+
self.connection_pool.release_connection
|
18
|
+
rescue Mysql2::Error => e
|
19
|
+
puts "Connection to #{db} Failed!"
|
20
|
+
puts e.message
|
21
|
+
end
|
22
|
+
return tables
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.exec_sql source_db,sql
|
26
|
+
DB.connect(source_db)
|
27
|
+
return DB.connection.execute(sql)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module VerticaUtils
|
2
|
+
class SourceDb < ActiveRecord::Base
|
3
|
+
|
4
|
+
def self.connect db
|
5
|
+
establish_connection(ActiveRecord::Base.configurations[db])
|
6
|
+
end
|
7
|
+
|
8
|
+
##
|
9
|
+
# Returns tables as an Array
|
10
|
+
# releases the connection
|
11
|
+
##
|
12
|
+
def self.get_tables(db)
|
13
|
+
tables = []
|
14
|
+
begin
|
15
|
+
self.connect(db)
|
16
|
+
tables = self.connection.tables
|
17
|
+
self.connection_pool.release_connection
|
18
|
+
rescue Mysql2::Error => e
|
19
|
+
puts "Connection to #{db} Failed!"
|
20
|
+
puts e.message
|
21
|
+
end
|
22
|
+
return tables
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.exec_sql source_db,sql
|
26
|
+
SourceDb.connect(source_db)
|
27
|
+
return SourceDb.connection.execute(sql)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Myreplicator
|
2
|
+
class VerticaTypes
|
3
|
+
|
4
|
+
def self.convert type, col_type
|
5
|
+
if mysql_vertica_conversion[type].blank?
|
6
|
+
return col_type
|
7
|
+
else
|
8
|
+
return mysql_vertica_conversion[type]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.mysql_vertica_conversion
|
13
|
+
map = {
|
14
|
+
"int" => "int",
|
15
|
+
"integer" => "int",
|
16
|
+
"int8" => "int",
|
17
|
+
"smallint" => "int",
|
18
|
+
"bigint" => "int",
|
19
|
+
"tinyint" => "int",
|
20
|
+
"numeric" => "int",
|
21
|
+
"text" => "VARCHAR(65000)",
|
22
|
+
"mediumtext" => "VARCHAR(65000)",
|
23
|
+
"bit" => "binary",
|
24
|
+
"longtext" => "VARCHAR(65000)",
|
25
|
+
"float" => "decimal"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.convert_key key
|
30
|
+
map = {
|
31
|
+
"UNI" => "UNIQUE",
|
32
|
+
" MUL" => "",
|
33
|
+
"PRI" => "PRIMARY KEY"
|
34
|
+
}
|
35
|
+
|
36
|
+
if map[key].blank?
|
37
|
+
return ""
|
38
|
+
else
|
39
|
+
return map[key]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|