myreplicator 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|