oracle_to_mysql 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/.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
|