dbgeni 0.10.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.
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