dbgeni 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +29 -0
  3. data/bin/dbgeni +2 -0
  4. data/lib/dbgeni/base.rb +146 -0
  5. data/lib/dbgeni/base_code.rb +143 -0
  6. data/lib/dbgeni/blank_slate.rb +24 -0
  7. data/lib/dbgeni/cli.rb +96 -0
  8. data/lib/dbgeni/code.rb +235 -0
  9. data/lib/dbgeni/code_list.rb +60 -0
  10. data/lib/dbgeni/commands/code.rb +151 -0
  11. data/lib/dbgeni/commands/commands.rb +41 -0
  12. data/lib/dbgeni/commands/config.rb +36 -0
  13. data/lib/dbgeni/commands/dmls.rb +244 -0
  14. data/lib/dbgeni/commands/generate.rb +257 -0
  15. data/lib/dbgeni/commands/initialize.rb +41 -0
  16. data/lib/dbgeni/commands/migrations.rb +243 -0
  17. data/lib/dbgeni/commands/milestones.rb +52 -0
  18. data/lib/dbgeni/commands/new.rb +178 -0
  19. data/lib/dbgeni/config.rb +325 -0
  20. data/lib/dbgeni/connectors/connector.rb +59 -0
  21. data/lib/dbgeni/connectors/mysql.rb +146 -0
  22. data/lib/dbgeni/connectors/oracle.rb +149 -0
  23. data/lib/dbgeni/connectors/sqlite.rb +166 -0
  24. data/lib/dbgeni/connectors/sybase.rb +97 -0
  25. data/lib/dbgeni/dml_cli.rb +35 -0
  26. data/lib/dbgeni/environment.rb +161 -0
  27. data/lib/dbgeni/exceptions/exception.rb +69 -0
  28. data/lib/dbgeni/file_converter.rb +44 -0
  29. data/lib/dbgeni/initializers/initializer.rb +44 -0
  30. data/lib/dbgeni/initializers/mysql.rb +36 -0
  31. data/lib/dbgeni/initializers/oracle.rb +38 -0
  32. data/lib/dbgeni/initializers/sqlite.rb +33 -0
  33. data/lib/dbgeni/initializers/sybase.rb +34 -0
  34. data/lib/dbgeni/logger.rb +60 -0
  35. data/lib/dbgeni/migration.rb +302 -0
  36. data/lib/dbgeni/migration_cli.rb +204 -0
  37. data/lib/dbgeni/migration_list.rb +91 -0
  38. data/lib/dbgeni/migrators/migrator.rb +40 -0
  39. data/lib/dbgeni/migrators/migrator_interface.rb +51 -0
  40. data/lib/dbgeni/migrators/mysql.rb +82 -0
  41. data/lib/dbgeni/migrators/oracle.rb +211 -0
  42. data/lib/dbgeni/migrators/sqlite.rb +90 -0
  43. data/lib/dbgeni/migrators/sybase.rb +118 -0
  44. data/lib/dbgeni/plugin.rb +92 -0
  45. data/lib/dbgeni.rb +52 -0
  46. metadata +87 -0
@@ -0,0 +1,204 @@
1
+ module DBGeni
2
+ class MigrationCLI
3
+
4
+ def initialize(base_installer, config, logger)
5
+ @base = base_installer
6
+ @config = config
7
+ @logger = logger
8
+ set_plugin_hooks
9
+ end
10
+
11
+ def migrations
12
+ @migration_list ||= DBGeni::MigrationList.new(@config.migration_directory) unless @migration_list
13
+ @migration_list.migrations
14
+ end
15
+
16
+ def outstanding_migrations
17
+ ensure_initialized
18
+ migrations
19
+ @migration_list.outstanding(@config, connection)
20
+ end
21
+
22
+ def applied_migrations
23
+ ensure_initialized
24
+ migrations
25
+ @migration_list.applied(@config, connection)
26
+ end
27
+
28
+ def applied_and_broken_migrations
29
+ ensure_initialized
30
+ migrations
31
+ @migration_list.applied_and_broken(@config, connection)
32
+ end
33
+
34
+ def list_of_migrations(list)
35
+ ensure_initialized
36
+ migrations
37
+ @migration_list.list(list, @config, connection)
38
+ end
39
+
40
+ # Applying
41
+
42
+ def apply_all_migrations(force=nil)
43
+ ensure_initialized
44
+ migrations = outstanding_migrations
45
+ if migrations.length == 0
46
+ raise DBGeni::NoOutstandingMigrations
47
+ end
48
+ apply_migration_list(migrations, force)
49
+ end
50
+
51
+ def apply_next_migration(force=nil)
52
+ ensure_initialized
53
+ migrations = outstanding_migrations
54
+ if migrations.length == 0
55
+ raise DBGeni::NoOutstandingMigrations
56
+ end
57
+ apply_migration_list([migrations.first], force)
58
+ end
59
+
60
+ def apply_until_migration(migration_name, force=nil)
61
+ ensure_initialized
62
+ milestone = find_migration(migration_name)
63
+ outstanding = outstanding_migrations
64
+ index = outstanding.index milestone
65
+ unless index
66
+ # milestone migration doesn't exist or is already applied.
67
+ raise MigrationNotOutstanding, milestone.to_s
68
+ end
69
+ apply_migration_list(outstanding[0..index], force)
70
+ end
71
+
72
+ def apply_list_of_migrations(migration_list, force=nil)
73
+ ensure_initialized
74
+ migration_files = list_of_migrations(migration_list)
75
+ apply_migration_list(migration_files, force)
76
+ end
77
+
78
+
79
+ def apply_migration(migration, force=nil)
80
+ ensure_initialized
81
+ begin
82
+ run_plugin(@before_up_run_plugin, migration)
83
+ migration.apply!(@config, connection, force)
84
+ @logger.info "Applied #{migration.to_s}"
85
+ run_plugin(@after_up_run_plugin, migration)
86
+ rescue DBGeni::MigratorCouldNotConnect
87
+ @logger.error "Failed to connect to the database CLI"
88
+ raise DBGeni::MigrationApplyFailed, migration.to_s
89
+ rescue DBGeni::MigrationApplyFailed
90
+ @logger.error "Failed #{migration.to_s}. Errors in #{migration.logfile}\n\n#{migration.error_messages}\n\n"
91
+ raise DBGeni::MigrationApplyFailed, migration.to_s
92
+ end
93
+ end
94
+
95
+ # rolling back
96
+
97
+ def rollback_all_migrations(force=nil)
98
+ ensure_initialized
99
+ migrations = applied_and_broken_migrations.reverse
100
+ if migrations.length == 0
101
+ raise DBGeni::NoAppliedMigrations
102
+ end
103
+ apply_migration_list(migrations, force, false)
104
+ end
105
+
106
+ def rollback_last_migration(force=nil)
107
+ ensure_initialized
108
+ migrations = applied_and_broken_migrations
109
+ if migrations.length == 0
110
+ raise DBGeni::NoAppliedMigrations
111
+ end
112
+ # the most recent one is at the end of the array!!
113
+ apply_migration_list([migrations.last], force, false)
114
+ end
115
+
116
+ def rollback_until_migration(migration_name, force=nil)
117
+ ensure_initialized
118
+ milestone = find_migration(migration_name)
119
+ applied = applied_and_broken_migrations.reverse
120
+ index = applied.index milestone
121
+ unless index
122
+ # milestone migration doesn't exist or is already applied.
123
+ raise DBGeni::MigrationNotApplied, milestone.to_s
124
+ end
125
+ # Note the triple ... in the range to exclude the end element
126
+ # This is because we don't want to rollback the final migration as its upto but not including
127
+ apply_migration_list(applied[0...index], force, false)
128
+ end
129
+
130
+ def rollback_list_of_migrations(migration_list, force=nil)
131
+ ensure_initialized
132
+ migration_files = list_of_migrations(migration_list).reverse
133
+ apply_migration_list(migration_files, force, false)
134
+ end
135
+
136
+ def rollback_migration(migration, force=nil)
137
+ ensure_initialized
138
+ begin
139
+ run_plugin(@before_down_run_plugin, migration)
140
+ migration.rollback!(@config, connection, force)
141
+ @logger.info "Rolledback #{migration.to_s}"
142
+ run_plugin(@after_down_run_plugin, migration)
143
+ rescue DBGeni::MigratorCouldNotConnect
144
+ @logger.error "Failed to connect to the database CLI"
145
+ raise DBGeni::MigrationApplyFailed, migration.to_s
146
+ rescue DBGeni::MigrationApplyFailed
147
+ @logger.error "Failed #{migration.to_s}. Errors in #{migration.logfile}\n\n#{migration.error_messages}\n\n"
148
+ raise DBGeni::MigrationApplyFailed, migration.to_s
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ def apply_migration_list(migration_list, force, up=true)
155
+ # TODO - conflicted about how to handle exceptions.
156
+ # If before_running_migrations throws an exception no
157
+ # migrations will be run.
158
+ # If a migration throws an exception, then after_running_migrations
159
+ # will not be run.
160
+ params = {
161
+ :operation => up == true ? 'apply' : 'remove'
162
+ }
163
+ run_plugin(@before_running_plugin, migration_list, params)
164
+ migration_list.each do |m|
165
+ if up
166
+ apply_migration(m, force)
167
+ else
168
+ rollback_migration(m, force)
169
+ end
170
+ end
171
+ run_plugin(@after_running_plugin, migration_list, params)
172
+ end
173
+
174
+ def run_plugin(hook, object, params={})
175
+ @base.run_plugin(hook, object, params)
176
+ end
177
+
178
+ private
179
+
180
+ def find_migration(migration_name)
181
+ m = Migration.initialize_from_internal_name(@config.migration_directory, migration_name)
182
+ end
183
+
184
+ def set_plugin_hooks
185
+ @before_up_run_plugin = :before_migration_up
186
+ @after_up_run_plugin = :after_migration_up
187
+ @before_down_run_plugin = :before_migration_down
188
+ @after_down_run_plugin = :after_migration_down
189
+ @before_running_plugin = :before_running_migrations
190
+ @after_running_plugin = :after_running_migrations
191
+ end
192
+
193
+
194
+ def ensure_initialized
195
+ @base.ensure_initialized
196
+ end
197
+
198
+ def connection
199
+ @base.connection
200
+ end
201
+
202
+
203
+ end
204
+ end
@@ -0,0 +1,91 @@
1
+ module DBGeni
2
+
3
+ class MigrationList
4
+
5
+ attr_reader :migrations
6
+ attr_reader :migration_directory
7
+
8
+ # This is a bit of a hack. DML migrations reuse all of migrations, infact they were forced in
9
+ # later as an afterthought, so each migration will initially have a type of 'Migration'. This
10
+ # changes it to DML.
11
+ def self.new_dml_migrations(migration_directory)
12
+ obj = self.new(migration_directory)
13
+ obj.migrations.each do |m|
14
+ m.migration_type = 'DML'
15
+ end
16
+ obj
17
+ end
18
+
19
+ def initialize(migration_directory)
20
+ @migration_directory = migration_directory
21
+ file_list
22
+ end
23
+
24
+ # Returns an array of MIGRATIONS that have been applied
25
+ # ordered by oldest first
26
+ def applied(config, connection)
27
+ migrations_with_status(config, connection, DBGeni::Migration::COMPLETED)
28
+ end
29
+
30
+ def outstanding(config, connection)
31
+ migrations_with_status(config, connection,
32
+ DBGeni::Migration::NEW,
33
+ DBGeni::Migration::ROLLEDBACK,
34
+ DBGeni::Migration::FAILED,
35
+ DBGeni::Migration::PENDING)
36
+ end
37
+
38
+ def applied_and_broken(config, connection)
39
+ migrations_with_status(config, connection,
40
+ DBGeni::Migration::COMPLETED,
41
+ DBGeni::Migration::FAILED,
42
+ DBGeni::Migration::PENDING)
43
+ end
44
+
45
+ def list(list_of_migrations, config, connection)
46
+ valid_migrations = []
47
+ list_of_migrations.each do |m|
48
+ mig_obj = Migration.initialize_from_internal_name(@migration_directory, m)
49
+ if i = @migrations.index(mig_obj)
50
+ valid_migrations.push @migrations[i]
51
+ else
52
+ raise DBGeni::MigrationFileNotExist, m
53
+ end
54
+ end
55
+ valid_migrations.sort {|x,y|
56
+ x.migration_file <=> y.migration_file
57
+ }
58
+ end
59
+
60
+
61
+ def migrations_with_status(config, connection, *args)
62
+ migrations = @migrations.select{|m|
63
+ args.include? m.status(config, connection)
64
+ }.sort {|x,y|
65
+ x.migration_file <=> y.migration_file
66
+ }
67
+ end
68
+
69
+ private
70
+
71
+ def file_list
72
+ begin
73
+ # Migrations usually come in pairs, so need to find just the 'up'
74
+ # ones here, otherwise there will be too many!
75
+ # The migration filename format is YYYYMMDDHHMM_<up / down >_title.sql
76
+ files = Dir.entries(@migration_directory).grep(/^\d{12}_up_.+\.sql$/).sort
77
+ rescue Exception => e
78
+ puts "Migrations directory: #{@migrations_directory}"
79
+ raise DBGeni::MigrationDirectoryNotExist, "Migrations directory: #{@migrations_directory}"
80
+ end
81
+ @migrations = Array.new
82
+ files.each do |f|
83
+ @migrations.push Migration.new(@migration_directory, f)
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+
@@ -0,0 +1,40 @@
1
+ module DBGeni
2
+
3
+ module Migrator
4
+
5
+ def self.initialize(config, connection)
6
+ required_class = setup(config.db_type)
7
+ begin
8
+ required_method = required_class.method("new")
9
+ rescue NameError
10
+ raise DBGeni::InvalidMigratorForDBType, config.db_type
11
+ end
12
+ required_method.call(config, connection)
13
+ end
14
+
15
+ # def self.logfile(filename)
16
+ # name = File.basename(filename)
17
+ # "#{Time.now.strftime('%Y%m%d%H%M%S')}_#{name}"
18
+ # end
19
+
20
+ private
21
+
22
+ def self.setup(db_type)
23
+ begin
24
+ require "dbgeni/migrators/#{db_type}"
25
+ rescue
26
+ raise DBGeni::NoMigratorForDBType, db_type
27
+ end
28
+
29
+ required_class = nil
30
+ if Migrator.const_defined?(db_type.capitalize)
31
+ required_class = Migrator.const_get(db_type.capitalize)
32
+ else
33
+ raise DBGeni::NoMigratorForDBType, db_type
34
+ end
35
+ required_class
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,51 @@
1
+ module DBGeni
2
+ module Migrator
3
+
4
+ class MigratorInterface
5
+
6
+ attr_reader :logfile
7
+
8
+ def apply(migration, force=nil)
9
+ run_in_client(migration.runnable_migration, force)
10
+ end
11
+
12
+ def rollback(migration, force=nil)
13
+ run_in_client(migration.runnable_rollback, force)
14
+ end
15
+
16
+ def migration_errors
17
+ end
18
+
19
+ def verify(migration)
20
+ raise DBGeni::NotImplemented
21
+ end
22
+
23
+ def compile(code, force=false)
24
+ run_in_client(code.runnable_code, force, true)
25
+ end
26
+
27
+ def remove(code, force=false)
28
+ raise DBGeni::NotImplemented
29
+ end
30
+
31
+ def code_errors
32
+ raise DBGeni::NotImplemented
33
+ end
34
+
35
+ private
36
+
37
+ def run_in_client(file, force, is_proc=false)
38
+ end
39
+
40
+ def initialize(config, connection)
41
+ @config = config
42
+ # this is not actually used to run in the sql script
43
+ @connection = connection
44
+ @logfile = nil
45
+ @log_dir = DBGeni::Logger.instance("#{@config.base_directory}/log").detailed_log_dir
46
+ ensure_executable_exists
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,82 @@
1
+ module DBGeni
2
+ module Migrator
3
+
4
+ class Mysql < DBGeni::Migrator::MigratorInterface
5
+
6
+ def initialize(config, connection)
7
+ super(config, connection)
8
+ end
9
+
10
+ # Defined in super ...
11
+ # def apply(migration, force=nil)
12
+ # end
13
+
14
+ # def rollback(migration, force=nil)
15
+ # end
16
+
17
+ def migration_errors
18
+ error = ''
19
+ # MYSQL prints the errors at the start of the log file
20
+ begin
21
+ fh = File.open(@logfile, 'r')
22
+ error = fh.readline
23
+ unless error =~ /^ERROR/
24
+ error = ''
25
+ end
26
+ ensure
27
+ fh.close if fh
28
+ end
29
+ error
30
+ end
31
+
32
+ def remove(code, force=false)
33
+ begin
34
+ @connection.execute(drop_command(code))
35
+ rescue Exception => e
36
+ unless e.to_s =~ /(procedure|function|trigger).+does not exist/i
37
+ raise DBGeni::CodeRemoveFailed, e.to_s
38
+ end
39
+ end
40
+ end
41
+
42
+ def code_errors
43
+ # In mysql the code errors ar just the same as migration errors
44
+ errors = migration_errors
45
+ if errors == ''
46
+ errors = nil
47
+ end
48
+ errors
49
+ end
50
+
51
+ private
52
+
53
+ def run_in_client(file, force, is_proc=false)
54
+ @logfile = "#{@log_dir}/#{File.basename(file)}"
55
+
56
+ z = @config.env
57
+ response = system("mysql -u#{z.username} -p#{z.password} -h#{z.hostname} -P#{z.port} -D#{z.database} -vvv #{force ? '--force' : ''} <#{file} >#{logfile} 2>&1")
58
+ unless response
59
+ raise DBGeni::MigrationContainsErrors
60
+ end
61
+ end
62
+
63
+ def ensure_executable_exists
64
+ unless Kernel.executable_exists?('mysql')
65
+ raise DBGeni::DBCLINotOnPath
66
+ end
67
+ end
68
+
69
+ def drop_command(code)
70
+ case code.type
71
+ when DBGeni::Code::TRIGGER
72
+ "drop trigger #{code.name.downcase}"
73
+ when DBGeni::Code::FUNCTION
74
+ "drop function #{code.name.downcase}"
75
+ when DBGeni::Code::PROCEDURE
76
+ "drop procedure #{code.name.downcase}"
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,211 @@
1
+ module DBGeni
2
+ module Migrator
3
+
4
+ class Oracle < DBGeni::Migrator::MigratorInterface
5
+
6
+ def initialize(config, connection)
7
+ super(config, connection)
8
+ end
9
+
10
+ # def apply(migration, force=nil)
11
+ # end
12
+
13
+ # def rollback(migration, force=nil)
14
+ # end
15
+
16
+ def migration_errors
17
+ has_errors = false
18
+ buffer = []
19
+
20
+ begin
21
+ File.open(@logfile, 'r').each_line do |l|
22
+ buffer.push l
23
+ if buffer.length > 10
24
+ buffer.shift
25
+ end
26
+ if !has_errors && l =~ /^ERROR at line/
27
+ has_errors = true
28
+ next
29
+ end
30
+ # After we find the ERROR at line, the next line contains the error
31
+ # message, so we just want to consume it and then exit.
32
+ # The line we care about will be in the buffer, so just break and join
33
+ # the buffer.
34
+ if has_errors
35
+ break
36
+ end
37
+ end
38
+ rescue Errno::ENOENT
39
+ # assume this means the log was never written as, generally because
40
+ # sqlplus didn't connect to Oracle. In this case do nothing
41
+ end
42
+ buffer.join("")
43
+ end
44
+
45
+ # def verify(migration)
46
+ # end
47
+
48
+ def compile(code, force=false)
49
+ run_in_client(code.runnable_code, force, true)
50
+ end
51
+
52
+ def remove(code, force=false)
53
+ begin
54
+ @connection.execute(drop_command(code))
55
+ rescue Exception => e
56
+ unless e.to_s =~ /(object|trigger) .+ does not exist/
57
+ raise DBGeni::CodeRemoveFailed, e.to_s
58
+ end
59
+ end
60
+ end
61
+
62
+ def code_errors
63
+ # The error part of the file file either looks like:
64
+
65
+ # SQL> show err
66
+ # No errors.
67
+ # SQL> spool off
68
+
69
+ # or
70
+
71
+ # SQL> show err
72
+ # Errors for PACKAGE BODY PKG1:
73
+
74
+ # LINE/COL ERROR
75
+ # -------- -----------------------------------------------------------------
76
+ # 5/1 PLS-00103: Encountered the symbol "END" when expecting one of the
77
+ # following:
78
+ # Error messages here
79
+ # SQL> spool off
80
+
81
+ # In the first case, return nil, but in the second case get everything after show err
82
+
83
+ error_msg = ''
84
+ start_search = false
85
+ File.open(@logfile, 'r').each_line do |l|
86
+ if !start_search && l =~ /^SQL> show err/
87
+ start_search = true
88
+ next
89
+ end
90
+ if start_search
91
+ if l =~ /^No errors\./
92
+ error_msg = nil
93
+ break
94
+ elsif l =~ /^SQL> spool off/
95
+ break
96
+ else
97
+ error_msg << l
98
+ end
99
+ end
100
+ end
101
+ error_msg
102
+ end
103
+
104
+ private
105
+
106
+ def run_in_client(file, force, is_proc=false)
107
+ null_device = '/dev/null'
108
+ if Kernel.is_windows?
109
+ null_device = 'NUL:'
110
+ end
111
+
112
+ @logfile = "#{@log_dir}/#{File.basename(file)}"
113
+
114
+ # sql_parameters = parameters
115
+ # unless parameters
116
+ # sql_parameters = checkSQLPlusParameters(file)
117
+ # end
118
+
119
+ add_terminator = true
120
+ if is_proc
121
+ add_terminator = !file_contains_terminator?(file)
122
+ end
123
+
124
+ IO.popen("sqlplus -L #{@config.env.username}/#{@config.env.password}@#{@config.env.database} > #{null_device}", "w") do |p|
125
+ p.puts "set TERM on"
126
+ p.puts "set ECHO on"
127
+ # if sql_parameters == ''
128
+ p.puts "set define off"
129
+ # end
130
+ unless force
131
+ p.puts "whenever sqlerror exit 200"
132
+ end
133
+ # p.puts "START #{File.basename(file)} #{sql_parameters}"
134
+ p.puts "spool #{@logfile}"
135
+ # Switch the current schema but only if the override is in the config file
136
+ if @config.env.install_schema
137
+ p.puts "alter session set current_schema=#{@config.env.install_schema};"
138
+ end
139
+ p.puts "START #{file}"
140
+ if is_proc
141
+ p.puts "/" if add_terminator
142
+ p.puts "show err"
143
+ end
144
+ p.puts "spool off"
145
+ p.puts "exit"
146
+ end
147
+ # When the pipe block ends, ruby sets $? with the exit status. A
148
+ # good exit status is 0 (zero) anything else means it went wrong
149
+ # If $? is anything but zero, raise an exception.
150
+ if $?.exitstatus != 0
151
+ if $?.exitstatus != 200
152
+ raise DBGeni::MigratorCouldNotConnect
153
+ end
154
+ # Code compile errors never get here as they don't make sqlplus abort.
155
+ # But if the user does not have privs to create the proc / trigger etc,
156
+ # the code will abort to here via a insufficient privs error. Or if the code
157
+ # file doesn't contain 'create or replace .... ' and just garbage it can get here.
158
+ raise DBGeni::MigrationContainsErrors
159
+ end
160
+ end
161
+
162
+ def ensure_executable_exists
163
+ unless Kernel.executable_exists?('sqlplus')
164
+ raise DBGeni::DBCLINotOnPath
165
+ end
166
+ end
167
+
168
+ def drop_command(code)
169
+ case code.type
170
+ when DBGeni::Code::PACKAGE_SPEC
171
+ "drop package #{code.name}"
172
+ when DBGeni::Code::PACKAGE_BODY
173
+ "drop package body #{code.name}"
174
+ when DBGeni::Code::TRIGGER
175
+ "drop trigger #{code.name}"
176
+ when DBGeni::Code::FUNCTION
177
+ "drop function #{code.name}"
178
+ when DBGeni::Code::PROCEDURE
179
+ "drop procedure #{code.name}"
180
+ when DBGeni::Code::TYPE
181
+ "drop type #{code.name}"
182
+ when DBGeni::Code::UNKNOWN
183
+ derive_drop_command_from_db(code.name)
184
+ end
185
+ end
186
+
187
+ def file_contains_terminator?(filename)
188
+ has_slash = false
189
+ File.open(filename, 'r').each_line do |l|
190
+ if l =~ /^\s*\/\s*$/
191
+ has_slash = true
192
+ break
193
+ end
194
+ end
195
+ has_slash
196
+ end
197
+
198
+ def derive_drop_command_from_db(object_name)
199
+ # This is tricky because of packages - will give two objects with the same name :-/
200
+ raise CannotRemoveUnknownObject
201
+
202
+ # owner = @config.env.install_schema ? @config.env.install_schema : @config.env.username
203
+ # results = @connection.execute ("select object_type
204
+ # from all_objects
205
+ # where owner = :b1 and object_name = b2", owner.upcase, object_name.upcase)
206
+ # unless results
207
+ end
208
+
209
+ end
210
+ end
211
+ end