oracle_to_mysql 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.specification +111 -0
- data/README.rdoc +118 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/lib/oracle_to_mysql.rb +80 -0
- data/lib/oracle_to_mysql/api_instance_methods.rb +94 -0
- data/lib/oracle_to_mysql/command.rb +45 -0
- data/lib/oracle_to_mysql/command/delete_temp_files.rb +16 -0
- data/lib/oracle_to_mysql/command/fork_and_execute_sqlplus_command.rb +61 -0
- data/lib/oracle_to_mysql/command/write_and_execute_mysql_commands_to_bash_file.rb +136 -0
- data/lib/oracle_to_mysql/command/write_and_execute_mysql_commands_to_bash_file_in_replace_mode.rb +51 -0
- data/lib/oracle_to_mysql/command/write_sqlplus_commands_to_file.rb +64 -0
- data/lib/oracle_to_mysql/must_override_instance_methods.rb +16 -0
- data/lib/oracle_to_mysql/optional_override_instance_methods.rb +65 -0
- data/lib/oracle_to_mysql/private_instance_methods.rb +80 -0
- data/lib/oracle_to_mysql/protected_class_methods.rb +18 -0
- data/oracle_to_mysql.gemspec +74 -0
- data/test/demo/ps_term_tbl.rb +63 -0
- data/test/demo/ps_term_tbl_accumulative.rb +11 -0
- data/test/demo/test_oracle_to_mysql_against_ps_term_tbl.rb +59 -0
- data/test/helper.rb +13 -0
- data/test/oracle_to_mysql.example.yml +13 -0
- data/test/test_against_ps_term_tbl_accumulative.rb +12 -0
- data/test/test_oracle_to_mysql.rb +7 -0
- metadata +124 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
class OracleToMysql::Command
|
2
|
+
attr_accessor :client_class
|
3
|
+
def info(msg)
|
4
|
+
self.output("[info] #{msg}")
|
5
|
+
end
|
6
|
+
def error(msg)
|
7
|
+
self.output("[ERROR] #{msg}")
|
8
|
+
raise OracleToMysql::CommandError.new("#{self.client_class.to_s}#otm_execute died on command=#{self.class.to_s}")
|
9
|
+
end
|
10
|
+
def warn(msg)
|
11
|
+
self.output("[WARN] #{msg}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def started(msg='')
|
15
|
+
self.output("[started t=#{self.client_class.otm_time_elapsed_since_otm_timestamp}]#{msg}")
|
16
|
+
end
|
17
|
+
|
18
|
+
def finished(msg='')
|
19
|
+
self.output("[finished t=#{self.client_class.otm_time_elapsed_since_otm_timestamp}]#{msg}")
|
20
|
+
end
|
21
|
+
|
22
|
+
# USE THE ones above if possible, it makes the output more uniform and easier to read/parse
|
23
|
+
# Stuff funnels to here, which propogates up to the client class
|
24
|
+
def output(msg)
|
25
|
+
self.client_class.otm_output("[#{self.class.to_s}]#{msg}")
|
26
|
+
end
|
27
|
+
|
28
|
+
# Client classes call this method
|
29
|
+
def execute
|
30
|
+
self.started
|
31
|
+
self.execute_internal
|
32
|
+
self.finished
|
33
|
+
end
|
34
|
+
|
35
|
+
# Commands should override this if they use temp files that need to be cleaned up
|
36
|
+
# The cleanup_temp_files_and_tables command reflects on all commands to find and delete things
|
37
|
+
# referenced in here
|
38
|
+
def temp_file_symbols
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
|
42
|
+
def execute_internal
|
43
|
+
raise "CHILDREN MUST OVERRIDE THIS"
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
class Command
|
3
|
+
class DeleteTempFiles < OracleToMysql::Command
|
4
|
+
def execute_internal
|
5
|
+
self.client_class.otm_all_temp_files.each do |temp_file|
|
6
|
+
begin
|
7
|
+
self.info("Deleting temp file, #{temp_file}")
|
8
|
+
File.unlink(temp_file)
|
9
|
+
rescue Errno::ENOENT => e
|
10
|
+
self.warn("Could not remove temp file #{temp_file}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
class Command
|
3
|
+
class ForkAndExecuteSqlplusCommand < OracleToMysql::Command
|
4
|
+
def command_line_invocation
|
5
|
+
username = self.client_class.otm_source_config_hash['username']
|
6
|
+
password = self.client_class.otm_source_config_hash['password']
|
7
|
+
tns = OracleToMysql.tns_string_from_config(self.client_class.otm_source_config_hash) #self.client_class.otm_source_config_hash['tns']
|
8
|
+
"sqlplus -S '#{username}/#{password}@#{tns}' @#{self.client_class.otm_get_file_name_for(:oracle_commands)}"
|
9
|
+
end
|
10
|
+
|
11
|
+
# overridden from parent to help CleanupTempFilesAndTables do it's job
|
12
|
+
#
|
13
|
+
def temp_file_symbols
|
14
|
+
[:oracle_output]
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_internal
|
18
|
+
stderr_str = ""
|
19
|
+
stdout_str = ""
|
20
|
+
the_command = self.command_line_invocation
|
21
|
+
self.started("sqlplus child being spawned")
|
22
|
+
unless
|
23
|
+
Open4::popen4(the_command) { |pid, stdin, stdout, stderr|
|
24
|
+
stderr_str = stderr.read
|
25
|
+
stdout_str = stdout.read
|
26
|
+
true
|
27
|
+
}
|
28
|
+
self.error("Could not execute #{the_command}")
|
29
|
+
# raise "[#{self.to_s}][create_#{deriv_type.to_s}_with_convert][MBF##{mbf.id.to_s}] Couldn't execute #{convert_cmd}"
|
30
|
+
end
|
31
|
+
self.finished("sqlplus process terminated")
|
32
|
+
|
33
|
+
if stderr_str.length > 0
|
34
|
+
self.error("sqlplus had stderr output: #{stderr_str}")
|
35
|
+
end
|
36
|
+
if stdout_str.length > 0
|
37
|
+
self.warn("sqlplus had stdout output: #{stdout_str}")
|
38
|
+
end
|
39
|
+
|
40
|
+
if File.exists?(self.client_class.otm_get_file_name_for(:oracle_output))
|
41
|
+
spooled_file_size = File.size(self.client_class.otm_get_file_name_for(:oracle_output))
|
42
|
+
sqlplus_file_size = File.size(self.client_class.otm_get_file_name_for(:oracle_commands))
|
43
|
+
|
44
|
+
# This sqlplus file will have the oracle message
|
45
|
+
if spooled_file_size > sqlplus_file_size
|
46
|
+
self.info("sqlplus spooled #{spooled_file_size} bytes of output to #{self.client_class.otm_get_file_name_for(:oracle_output)}")
|
47
|
+
else
|
48
|
+
source_output_contents = IO.read(self.client_class.otm_get_file_name_for(:oracle_output))
|
49
|
+
self.warn("tiny data output: smaller than the sqlplus commands file, #{spooled_file_size} bytes, it might contains errors rather than data, I will check for Oracle error strings in #{self.client_class.otm_get_file_name_for(:oracle_output)} and die if so")
|
50
|
+
if source_output_contents.match(/^ERROR at line/) && source_output_contents.match(/^ORA-/)
|
51
|
+
self.error("sqlplus error: #{self.client_class.otm_get_file_name_for(:oracle_output)} contains both \"ERROR at line\" and \"ORA-\" in it, check it out, contents=#{source_output_contents}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
self.error("#{self.client_class.otm_get_file_name_for(:oracle_output)} does not exist")
|
56
|
+
end
|
57
|
+
self.info("sqlplus returned successfully")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
class Command
|
3
|
+
class WriteAndExecuteMysqlCommandsToBashFile < OracleToMysql::Command
|
4
|
+
|
5
|
+
def tables_to_retain
|
6
|
+
self.client_class.otm_retain_options[:n]
|
7
|
+
end
|
8
|
+
|
9
|
+
# Done this way so the child, _in_replace_mode, can override this
|
10
|
+
#
|
11
|
+
def mysql_command_order
|
12
|
+
[:execute_otm_target_sql,
|
13
|
+
:execute_temp_file_modded_otm_target_sql,
|
14
|
+
:load_data_infile,
|
15
|
+
:drop_expired_retained_tables,
|
16
|
+
:perform_atomic_rename_of_tables
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
########## MYSQL queryies/commands BEGIN
|
21
|
+
|
22
|
+
def execute_otm_target_sql
|
23
|
+
self.client_class.otm_target_sql
|
24
|
+
end
|
25
|
+
|
26
|
+
# The client class should not have to know about otm_temp_target_table
|
27
|
+
# this overrides it just for this instance so the otm_target_sql
|
28
|
+
# gets the temp table name interpolated into it instead of the actual
|
29
|
+
# this is done this way to support the non-atomic rename strategy as well (which does not create a temp table)
|
30
|
+
#
|
31
|
+
def execute_temp_file_modded_otm_target_sql
|
32
|
+
the_modded_client_class_inst = self.client_class.clone
|
33
|
+
the_modded_client_class_inst.instance_eval(<<-EOS, __FILE__,__LINE__)
|
34
|
+
def otm_target_table
|
35
|
+
"#{self.client_class.otm_temp_target_table}"
|
36
|
+
end
|
37
|
+
EOS
|
38
|
+
the_modded_client_class_inst.otm_target_sql
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_data_infile
|
42
|
+
"-- Rip through the oracle output data and insert into mysql
|
43
|
+
load data local infile '#{self.client_class.otm_get_file_name_for(:oracle_output)}'
|
44
|
+
into table #{self.client_class.otm_temp_target_table}
|
45
|
+
fields terminated by '\\t'
|
46
|
+
lines terminated by '\\n'
|
47
|
+
"
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_actual_target_table_if_it_doesnt_exist
|
51
|
+
# If this is the first run, the destination table won't exist yet. If that's the
|
52
|
+
# case, create an empty table so the atomic rename works
|
53
|
+
"create table if not exists #{self.client_class.otm_target_table}
|
54
|
+
select * from #{self.client_class.otm_temp_target_table} where 1=0"
|
55
|
+
end
|
56
|
+
|
57
|
+
def drop_expired_retained_tables
|
58
|
+
raise "TODO: not implemented yet for retention :n != 1" if tables_to_retain != 1
|
59
|
+
"drop table if exists #{self.client_class.otm_retained_target_table(tables_to_retain)}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def perform_atomic_rename_of_tables
|
63
|
+
raise "TODO: not implemented yet for retention :n != 1" if tables_to_retain != 1
|
64
|
+
"RENAME table
|
65
|
+
#{self.client_class.otm_target_table} TO #{self.client_class.otm_retained_target_table(tables_to_retain)},
|
66
|
+
#{self.client_class.otm_temp_target_table} TO #{self.client_class.otm_target_table}"
|
67
|
+
# rename table #{self.otm_retained_target_table}
|
68
|
+
#
|
69
|
+
#
|
70
|
+
# #{self.client_class.otm_target_table} to #{self.client_class.otm_target_table}_old, #{self.client_class.otm_temp_target_table} to #{self.client_class.otm_target_table};
|
71
|
+
#
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
########## MYSQL queryies/commands END
|
76
|
+
|
77
|
+
# -- Reflect the table retain options
|
78
|
+
# #{drop_expired_retained_tables_sql};
|
79
|
+
|
80
|
+
def the_mysql_commands
|
81
|
+
the_queries = ''
|
82
|
+
self.mysql_command_order.each do |mysql_command|
|
83
|
+
the_queries << "-- #{mysql_command.to_s}\n" # to make debugging easier
|
84
|
+
the_queries << self.send(mysql_command)
|
85
|
+
the_queries << ";\n"
|
86
|
+
end
|
87
|
+
the_queries
|
88
|
+
end
|
89
|
+
|
90
|
+
def command_line_invocation
|
91
|
+
h = self.client_class.otm_target_config_hash
|
92
|
+
"mysql -u'#{h['username']}' -h'#{h['host']}' -p'#{h['password']}' #{h['database']} < '#{self.client_class.otm_get_file_name_for(:mysql_commands)}'"
|
93
|
+
end
|
94
|
+
|
95
|
+
# overridden from parent to help CleanupTempFilesAndTables do it's job
|
96
|
+
#
|
97
|
+
def temp_file_symbols
|
98
|
+
[:mysql_commands]
|
99
|
+
end
|
100
|
+
|
101
|
+
def execute_internal
|
102
|
+
bytes_written = 0
|
103
|
+
the_mysql_commands_file = self.client_class.otm_get_file_name_for(:mysql_commands)
|
104
|
+
File.open(the_mysql_commands_file,'w') do |f|
|
105
|
+
bytes_written = f.write(self.the_mysql_commands)
|
106
|
+
end
|
107
|
+
if bytes_written > 0
|
108
|
+
self.info("#{bytes_written} bytes written to #{the_mysql_commands_file}")
|
109
|
+
else
|
110
|
+
self.error("Could not write to #{the_mysql_commands_file}")
|
111
|
+
end
|
112
|
+
|
113
|
+
stderr_str = ""
|
114
|
+
stdout_str = ""
|
115
|
+
the_command = self.command_line_invocation
|
116
|
+
self.started("mysql child being spawned")
|
117
|
+
unless
|
118
|
+
Open4::popen4(the_command) { |pid, stdin, stdout, stderr|
|
119
|
+
stderr_str = stderr.read
|
120
|
+
stdout_str = stdout.read
|
121
|
+
true
|
122
|
+
}
|
123
|
+
self.error("Could not execute #{the_command}")
|
124
|
+
end
|
125
|
+
self.finished("mysql child terminated")
|
126
|
+
|
127
|
+
if stderr_str.length > 0
|
128
|
+
self.error("mysql child process had stderr output: #{stderr_str}")
|
129
|
+
end
|
130
|
+
if stdout_str.length > 0
|
131
|
+
self.warn("mysql child process: #{stdout_str}")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
data/lib/oracle_to_mysql/command/write_and_execute_mysql_commands_to_bash_file_in_replace_mode.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
class Command
|
3
|
+
class WriteAndExecuteMysqlCommandsToBashFileInReplaceMode < OracleToMysql::Command::WriteAndExecuteMysqlCommandsToBashFile
|
4
|
+
|
5
|
+
# OVERRIDDEN
|
6
|
+
def mysql_command_order
|
7
|
+
[:execute_otm_target_sql,
|
8
|
+
:drop_expired_retained_tables, # defined in parent
|
9
|
+
:retention_policy_create_and_populate_tables,
|
10
|
+
:load_data_infile # overridden in this class
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
### MYSQL COMMANDS BEGIN
|
15
|
+
|
16
|
+
def retention_policy_create_and_populate_tables
|
17
|
+
raise "TODO: not implemented yet for retention :n != 1" if self.tables_to_retain != 1
|
18
|
+
the_modded_client_class_inst = self.client_class.clone
|
19
|
+
the_modded_client_class_inst.instance_eval(<<-EOS, __FILE__,__LINE__)
|
20
|
+
def otm_target_table
|
21
|
+
"#{self.client_class.otm_retained_target_table(tables_to_retain)}"
|
22
|
+
end
|
23
|
+
EOS
|
24
|
+
|
25
|
+
return_this = ''
|
26
|
+
return_this << the_modded_client_class_inst.otm_target_sql
|
27
|
+
return_this << ";\n"
|
28
|
+
return_this << "-- Insert existing rows into the retention table\n"
|
29
|
+
return_this << "INSERT INTO #{the_modded_client_class_inst.otm_target_table} SELECT * FROM #{self.client_class.otm_target_table}\n"
|
30
|
+
return_this
|
31
|
+
end
|
32
|
+
|
33
|
+
# Mostly the same as parent class except:
|
34
|
+
# * the replace key word which will replace existing rows on the target when there are mysql duplicate key errors
|
35
|
+
# possible todo: support "ignore" instead of "replace" (i have no reason to do this)
|
36
|
+
# * it copied into the otm_target_table directly rather than the temp table
|
37
|
+
#
|
38
|
+
def load_data_infile
|
39
|
+
"-- Rip through the oracle output data and insert into mysql
|
40
|
+
load data local infile '#{self.client_class.otm_get_file_name_for(:oracle_output)}'
|
41
|
+
replace
|
42
|
+
into table #{self.client_class.otm_target_table}
|
43
|
+
fields terminated by '\\t'
|
44
|
+
lines terminated by '\\n'
|
45
|
+
"
|
46
|
+
end
|
47
|
+
|
48
|
+
### MYSQL COMMANDS END
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
class Command
|
3
|
+
class WriterSqlplusCommandsToFile < OracleToMysql::Command
|
4
|
+
class MaxLineExceeded < Exception; end
|
5
|
+
# Oracle and sqlplus is so finicky, this captures some of the errors I've come across,
|
6
|
+
# it is not exhuastive
|
7
|
+
def validate_otm_source_sql
|
8
|
+
the_source_sql = self.client_class.otm_source_sql
|
9
|
+
|
10
|
+
# last character minus white space must be a ";"
|
11
|
+
raise "otm_source_sql not terminated with a ';'" if the_source_sql.strip[-1..-1] != ';'
|
12
|
+
|
13
|
+
# Detect and prevent sqlplus from SP2-0027: Input is too long (> 2499 characters) - line ignored
|
14
|
+
the_source_sql.each_line {|x| raise MaxLineExceeded.new("Ruby detection and prevention of Oracle error SP2-0027: Input is too long (> 2499 characters) - line ignored") if x.length > 2499}
|
15
|
+
|
16
|
+
# other sqlplus CAVEATS (that could be programmed, TODO-ish)
|
17
|
+
# If you're "IN" statements has more than 1000 elements, Oracle will barf out a ORA-01795 error
|
18
|
+
#
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def string_to_write_commands_file_name
|
23
|
+
self.validate_otm_source_sql
|
24
|
+
the_file_to_spool_output_to = self.client_class.otm_get_file_name_for(:oracle_output)
|
25
|
+
return "
|
26
|
+
WHENEVER SQLERROR EXIT 2;
|
27
|
+
spool on;
|
28
|
+
set heading off
|
29
|
+
set echo off
|
30
|
+
set verify off
|
31
|
+
set termout off
|
32
|
+
SET NEWPAGE 0;
|
33
|
+
SET SPACE 0;
|
34
|
+
SET PAGESIZE 0;
|
35
|
+
SET FEEDBACK OFF;
|
36
|
+
SET TRIMSPOOL ON;
|
37
|
+
SET TAB OFF;
|
38
|
+
set linesize 2000;
|
39
|
+
spool #{the_file_to_spool_output_to}
|
40
|
+
#{self.client_class.otm_source_sql}
|
41
|
+
spool off;
|
42
|
+
exit;
|
43
|
+
"
|
44
|
+
end
|
45
|
+
# overridden from parent to help CleanupTempFilesAndTables do it's job
|
46
|
+
#
|
47
|
+
def temp_file_symbols
|
48
|
+
[:oracle_commands]
|
49
|
+
end
|
50
|
+
|
51
|
+
def execute_internal
|
52
|
+
bytes_written = 0
|
53
|
+
File.open(self.client_class.otm_get_file_name_for(:oracle_commands),'w') do |f|
|
54
|
+
bytes_written = f.write(self.string_to_write_commands_file_name)
|
55
|
+
end
|
56
|
+
if bytes_written > 0
|
57
|
+
self.info("#{bytes_written} bytes written to #{self.client_class.otm_get_file_name_for(:oracle_commands)}")
|
58
|
+
else
|
59
|
+
self.error("could not write to #{self.client_class.otm_get_file_name_for(:oracle_commands)}, bytes_written=#{bytes_written}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
module MustOverrideInstanceMethods
|
3
|
+
|
4
|
+
|
5
|
+
#### MUST BE OVERRIDEN
|
6
|
+
def otm_source_sql
|
7
|
+
raise "YOU MUST OVERRIDE THIS"
|
8
|
+
end
|
9
|
+
def otm_target_sql
|
10
|
+
raise "YOU MUST OVERRIDE THIS"
|
11
|
+
end
|
12
|
+
def otm_target_table
|
13
|
+
raise "YOU MUST OVERRIDE THIS"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module OracleToMysql
|
2
|
+
module OptionalOverrideInstanceMethods
|
3
|
+
|
4
|
+
# YOU WILL OFTEN WANT TO OVERRIDE THIS,
|
5
|
+
def otm_strategy
|
6
|
+
if @otm_strategy.nil?
|
7
|
+
@otm_strategy = self.class.otm_default_strategy
|
8
|
+
end
|
9
|
+
@otm_strategy
|
10
|
+
end
|
11
|
+
|
12
|
+
# TO CHANGE the retain options, override this method
|
13
|
+
#
|
14
|
+
def otm_retain_options
|
15
|
+
if @otm_retain_options.nil?
|
16
|
+
@otm_retain_options = self.class.otm_default_retain_options
|
17
|
+
end
|
18
|
+
@otm_retain_options
|
19
|
+
end
|
20
|
+
|
21
|
+
def otm_source_config_hash
|
22
|
+
if self.otm_config_hash.has_key?('oracle_source')
|
23
|
+
return otm_config_hash['oracle_source']
|
24
|
+
else
|
25
|
+
raise "Could not find oracle_source key in config file #{self.otm_config_file}, you should override this method"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def otm_target_config_hash
|
29
|
+
if self.otm_config_hash.has_key?('mysql_target')
|
30
|
+
return otm_config_hash['mysql_target']
|
31
|
+
else
|
32
|
+
raise "Could not find mysql_target key in config file #{self.otm_config_file}, you should override this method"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Override this if you have zany rules about where your config file is, there is a handy otm_config_hash method in the ApiInstanceMethods
|
37
|
+
# you can use to get stuff outta here
|
38
|
+
#
|
39
|
+
def otm_config_file
|
40
|
+
non_rails_path = File.join(Dir.pwd, 'oracle_to_mysql.yml')
|
41
|
+
if defined?(RAILS_ROOT)
|
42
|
+
rails_path = File.join(RAILS_ROOT,'config','database.yml')
|
43
|
+
if rails_path
|
44
|
+
@otm_db_config_yml_file_name = rails_path
|
45
|
+
else
|
46
|
+
raise "Weird, RAILS_ROOT detected but no databases.yml, something is amiss!"
|
47
|
+
end
|
48
|
+
elsif File.exists?(non_rails_path)
|
49
|
+
@otm_db_config_yml_file_name = non_rails_path
|
50
|
+
else
|
51
|
+
raise "ERROR: No otm config file found"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# This is the table name that is created first on the server for the :atomic_rename strategy
|
56
|
+
#
|
57
|
+
def otm_temp_target_table
|
58
|
+
"#{self.otm_target_table}_#{self.otm_timestamp.to_i}_temp"
|
59
|
+
end
|
60
|
+
|
61
|
+
def tmp_directory
|
62
|
+
"/tmp"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|