activerecord-jdbc-adapter 0.6

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 (65) hide show
  1. data/History.txt +61 -0
  2. data/LICENSE +21 -0
  3. data/Manifest.txt +64 -0
  4. data/README.txt +116 -0
  5. data/Rakefile +146 -0
  6. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  7. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  8. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  9. data/lib/active_record/connection_adapters/jdbc_adapter.rb +575 -0
  10. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +10 -0
  11. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  12. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  13. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  15. data/lib/jdbc_adapter.rb +32 -0
  16. data/lib/jdbc_adapter/jdbc_db2.rb +104 -0
  17. data/lib/jdbc_adapter/jdbc_derby.rb +362 -0
  18. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  19. data/lib/jdbc_adapter/jdbc_hsqldb.rb +168 -0
  20. data/lib/jdbc_adapter/jdbc_mimer.rb +134 -0
  21. data/lib/jdbc_adapter/jdbc_mssql.rb +356 -0
  22. data/lib/jdbc_adapter/jdbc_mysql.rb +168 -0
  23. data/lib/jdbc_adapter/jdbc_oracle.rb +340 -0
  24. data/lib/jdbc_adapter/jdbc_postgre.rb +347 -0
  25. data/lib/jdbc_adapter/missing_functionality_helper.rb +72 -0
  26. data/lib/jdbc_adapter/version.rb +5 -0
  27. data/lib/jdbc_adapter_internal.jar +0 -0
  28. data/lib/tasks/jdbc_databases.rake +72 -0
  29. data/src/java/JDBCDerbySpec.java +323 -0
  30. data/src/java/JDBCMySQLSpec.java +89 -0
  31. data/src/java/JdbcAdapterInternalService.java +953 -0
  32. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  33. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  34. data/test/db/derby.rb +18 -0
  35. data/test/db/h2.rb +11 -0
  36. data/test/db/hsqldb.rb +15 -0
  37. data/test/db/jdbc.rb +11 -0
  38. data/test/db/jndi_config.rb +30 -0
  39. data/test/db/logger.rb +3 -0
  40. data/test/db/mysql.rb +9 -0
  41. data/test/db/postgres.rb +9 -0
  42. data/test/derby_multibyte_test.rb +12 -0
  43. data/test/derby_simple_test.rb +12 -0
  44. data/test/generic_jdbc_connection_test.rb +9 -0
  45. data/test/h2_simple_test.rb +7 -0
  46. data/test/hsqldb_simple_test.rb +6 -0
  47. data/test/jdbc_adapter/jdbc_db2_test.rb +21 -0
  48. data/test/jdbc_common.rb +6 -0
  49. data/test/jndi_test.rb +37 -0
  50. data/test/manualTestDatabase.rb +195 -0
  51. data/test/minirunit.rb +109 -0
  52. data/test/minirunit/testConnect.rb +14 -0
  53. data/test/minirunit/testH2.rb +73 -0
  54. data/test/minirunit/testHsqldb.rb +73 -0
  55. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  56. data/test/minirunit/testMysql.rb +83 -0
  57. data/test/minirunit/testRawSelect.rb +24 -0
  58. data/test/models/auto_id.rb +18 -0
  59. data/test/models/data_types.rb +18 -0
  60. data/test/models/entry.rb +20 -0
  61. data/test/mysql_multibyte_test.rb +6 -0
  62. data/test/mysql_simple_test.rb +13 -0
  63. data/test/postgres_simple_test.rb +12 -0
  64. data/test/simple.rb +157 -0
  65. metadata +112 -0
@@ -0,0 +1,347 @@
1
+ module ::JdbcSpec
2
+ module ActiveRecordExtensions
3
+ def postgresql_connection(config)
4
+ config[:port] ||= 5432
5
+ config[:url] ||= "jdbc:postgresql://#{config[:host]}:#{config[:port]}/#{config[:database]}"
6
+ config[:driver] ||= "org.postgresql.Driver"
7
+ jdbc_connection(config)
8
+ end
9
+ end
10
+
11
+ module PostgreSQL
12
+ def self.column_selector
13
+ [/postgre/i, lambda {|cfg,col| col.extend(::JdbcSpec::PostgreSQL::Column)}]
14
+ end
15
+
16
+ def self.adapter_selector
17
+ [/postgre/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::PostgreSQL)}]
18
+ end
19
+
20
+ module Column
21
+ def type_cast(value)
22
+ case type
23
+ when :boolean then cast_to_boolean(value)
24
+ else super
25
+ end
26
+ end
27
+
28
+ def simplified_type(field_type)
29
+ return :integer if field_type =~ /^serial/i
30
+ return :string if field_type =~ /\[\]$/i || field_type =~ /^interval/i
31
+ return :string if field_type =~ /^(?:point|lseg|box|"?path"?|polygon|circle)/i
32
+ return :datetime if field_type =~ /^timestamp/i
33
+ return :float if field_type =~ /^real|^money/i
34
+ return :binary if field_type =~ /^bytea/i
35
+ return :boolean if field_type =~ /^bool/i
36
+ super
37
+ end
38
+
39
+ def cast_to_boolean(value)
40
+ if value == true || value == false
41
+ value
42
+ else
43
+ %w(true t 1).include?(value.to_s.downcase)
44
+ end
45
+ end
46
+
47
+ def cast_to_date_or_time(value)
48
+ return value if value.is_a? Date
49
+ return nil if value.blank?
50
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
51
+ end
52
+
53
+ def cast_to_time(value)
54
+ return value if value.is_a? Time
55
+ time_array = ParseDate.parsedate value
56
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
57
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
58
+ end
59
+
60
+ def guess_date_or_time(value)
61
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
62
+ Date.new(value.year, value.month, value.day) : value
63
+ end
64
+
65
+ def default_value(value)
66
+ # Boolean types
67
+ return "t" if value =~ /true/i
68
+ return "f" if value =~ /false/i
69
+
70
+ # Char/String/Bytea type values
71
+ return $1 if value =~ /^'(.*)'::(bpchar|text|character varying|bytea)$/
72
+
73
+ # Numeric values
74
+ return value if value =~ /^-?[0-9]+(\.[0-9]*)?/
75
+
76
+ # Fixed dates / timestamp
77
+ return $1 if value =~ /^'(.+)'::(date|timestamp)/
78
+
79
+ # Anything else is blank, some user type, or some function
80
+ # and we can't know the value of that, so return nil.
81
+ return nil
82
+ end
83
+ end
84
+
85
+ def modify_types(tp)
86
+ tp[:primary_key] = "serial primary key"
87
+ tp[:string][:limit] = 255
88
+ tp[:integer][:limit] = nil
89
+ tp[:boolean][:limit] = nil
90
+ tp
91
+ end
92
+
93
+ def default_sequence_name(table_name, pk = nil)
94
+ default_pk, default_seq = pk_and_sequence_for(table_name)
95
+ default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
96
+ end
97
+
98
+ # Resets sequence to the max value of the table's pk if present.
99
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
100
+ unless pk and sequence
101
+ default_pk, default_sequence = pk_and_sequence_for(table)
102
+ pk ||= default_pk
103
+ sequence ||= default_sequence
104
+ end
105
+ if pk
106
+ if sequence
107
+ select_value <<-end_sql, 'Reset sequence'
108
+ SELECT setval('#{sequence}', (SELECT COALESCE(MAX(#{pk})+(SELECT increment_by FROM #{sequence}), (SELECT min_value FROM #{sequence})) FROM #{table}), false)
109
+ end_sql
110
+ else
111
+ @logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
112
+ end
113
+ end
114
+ end
115
+
116
+ # Find a table's primary key and sequence.
117
+ def pk_and_sequence_for(table)
118
+ # First try looking for a sequence with a dependency on the
119
+ # given table's primary key.
120
+ result = select(<<-end_sql, 'PK and serial sequence')[0]
121
+ SELECT attr.attname AS nm, name.nspname AS nsp, seq.relname AS rel
122
+ FROM pg_class seq,
123
+ pg_attribute attr,
124
+ pg_depend dep,
125
+ pg_namespace name,
126
+ pg_constraint cons
127
+ WHERE seq.oid = dep.objid
128
+ AND seq.relnamespace = name.oid
129
+ AND seq.relkind = 'S'
130
+ AND attr.attrelid = dep.refobjid
131
+ AND attr.attnum = dep.refobjsubid
132
+ AND attr.attrelid = cons.conrelid
133
+ AND attr.attnum = cons.conkey[1]
134
+ AND cons.contype = 'p'
135
+ AND dep.refobjid = '#{table}'::regclass
136
+ end_sql
137
+
138
+ if result.nil? or result.empty?
139
+ # If that fails, try parsing the primary key's default value.
140
+ # Support the 7.x and 8.0 nextval('foo'::text) as well as
141
+ # the 8.1+ nextval('foo'::regclass).
142
+ # TODO: assumes sequence is in same schema as table.
143
+ result = select(<<-end_sql, 'PK and custom sequence')[0]
144
+ SELECT attr.attname AS nm, name.nspname AS nsp, split_part(def.adsrc, '\\\'', 2) AS rel
145
+ FROM pg_class t
146
+ JOIN pg_namespace name ON (t.relnamespace = name.oid)
147
+ JOIN pg_attribute attr ON (t.oid = attrelid)
148
+ JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
149
+ JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
150
+ WHERE t.oid = '#{table}'::regclass
151
+ AND cons.contype = 'p'
152
+ AND def.adsrc ~* 'nextval'
153
+ end_sql
154
+ end
155
+ # check for existence of . in sequence name as in public.foo_sequence. if it does not exist, join the current namespace
156
+ result['rel']['.'] ? [result['nm'], result['rel']] : [result['nm'], "#{result['nsp']}.#{result['rel']}"]
157
+ rescue
158
+ nil
159
+ end
160
+
161
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
162
+ execute(sql, name)
163
+ table = sql.split(" ", 4)[2]
164
+ id_value || last_insert_id(table, sequence_name || default_sequence_name(table, pk))
165
+ end
166
+
167
+ def columns(table_name, name=nil)
168
+ schema_name = "public"
169
+ if table_name =~ /\./
170
+ parts = table_name.split(/\./)
171
+ table_name = parts.pop
172
+ schema_name = parts.join(".")
173
+ end
174
+ @connection.columns_internal(table_name, name, schema_name)
175
+ end
176
+
177
+ def last_insert_id(table, sequence_name)
178
+ Integer(select_value("SELECT currval('#{sequence_name}')"))
179
+ end
180
+
181
+ # the point here is really just to empty the database, not recreate it
182
+ # so we delete all tables
183
+ def recreate_database(name)
184
+ tables.each{|t| drop_table(t)}
185
+ end
186
+
187
+ def structure_dump
188
+ abcs = ActiveRecord::Base.configurations
189
+
190
+ database = nil
191
+ if abcs[RAILS_ENV]["url"] =~ /\/([^\/]*)$/
192
+ database = $1
193
+ else
194
+ raise "Could not figure out what database this url is for #{abcs[RAILS_ENV]["url"]}"
195
+ end
196
+
197
+ ENV['PGHOST'] = abcs[RAILS_ENV]["host"] if abcs[RAILS_ENV]["host"]
198
+ ENV['PGPORT'] = abcs[RAILS_ENV]["port"].to_s if abcs[RAILS_ENV]["port"]
199
+ ENV['PGPASSWORD'] = abcs[RAILS_ENV]["password"].to_s if abcs[RAILS_ENV]["password"]
200
+ search_path = abcs[RAILS_ENV]["schema_search_path"]
201
+ search_path = "--schema=#{search_path}" if search_path
202
+
203
+ @connection.connection.close
204
+ begin
205
+ file = "db/#{RAILS_ENV}_structure.sql"
206
+ `pg_dump -i -U "#{abcs[RAILS_ENV]["username"]}" -s -x -O -f #{file} #{search_path} #{database}`
207
+ raise "Error dumping database" if $?.exitstatus == 1
208
+
209
+ # need to patch away any references to SQL_ASCII as it breaks the JDBC driver
210
+ lines = File.readlines(file)
211
+ File.open(file, "w") do |io|
212
+ lines.each do |line|
213
+ line.gsub!(/SQL_ASCII/, 'UNICODE')
214
+ io.write(line)
215
+ end
216
+ end
217
+ ensure
218
+ reconnect!
219
+ end
220
+ end
221
+
222
+ def _execute(sql, name = nil)
223
+ case sql.strip
224
+ when /\A\(?\s*(select|show)/i:
225
+ @connection.execute_query(sql)
226
+ else
227
+ @connection.execute_update(sql)
228
+ end
229
+ end
230
+
231
+ # SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
232
+ #
233
+ # PostgreSQL requires the ORDER BY columns in the select list for distinct queries, and
234
+ # requires that the ORDER BY include the distinct column.
235
+ #
236
+ # distinct("posts.id", "posts.created_at desc")
237
+ def distinct(columns, order_by)
238
+ return "DISTINCT #{columns}" if order_by.blank?
239
+
240
+ # construct a clean list of column names from the ORDER BY clause, removing
241
+ # any asc/desc modifiers
242
+ order_columns = order_by.split(',').collect { |s| s.split.first }
243
+ order_columns.delete_if(&:blank?)
244
+ order_columns = order_columns.zip((0...order_columns.size).to_a).map { |s,i| "#{s} AS alias_#{i}" }
245
+
246
+ # return a DISTINCT ON() clause that's distinct on the columns we want but includes
247
+ # all the required columns for the ORDER BY to work properly
248
+ sql = "DISTINCT ON (#{columns}) #{columns}, "
249
+ sql << order_columns * ', '
250
+ end
251
+
252
+ # ORDER BY clause for the passed order option.
253
+ #
254
+ # PostgreSQL does not allow arbitrary ordering when using DISTINCT ON, so we work around this
255
+ # by wrapping the sql as a sub-select and ordering in that query.
256
+ def add_order_by_for_association_limiting!(sql, options)
257
+ return sql if options[:order].blank?
258
+
259
+ order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
260
+ order.map! { |s| 'DESC' if s =~ /\bdesc$/i }
261
+ order = order.zip((0...order.size).to_a).map { |s,i| "id_list.alias_#{i} #{s}" }.join(', ')
262
+
263
+ sql.replace "SELECT * FROM (#{sql}) AS id_list ORDER BY #{order}"
264
+ end
265
+
266
+ def quote(value, column = nil)
267
+ return value.quoted_id if value.respond_to?(:quoted_id)
268
+
269
+ if value.kind_of?(String) && column && column.type == :binary
270
+ "'#{escape_bytea(value)}'"
271
+ elsif column && column.type == :primary_key
272
+ return value.to_s
273
+ else
274
+ super
275
+ end
276
+ end
277
+
278
+ def escape_bytea(s)
279
+ if s
280
+ result = ''
281
+ s.each_byte { |c| result << sprintf('\\\\%03o', c) }
282
+ result
283
+ end
284
+ end
285
+
286
+ def quote_column_name(name)
287
+ %("#{name}")
288
+ end
289
+
290
+ def quoted_date(value)
291
+ value.strftime("%Y-%m-%d %H:%M:%S.#{sprintf("%06d", value.usec)}")
292
+ end
293
+
294
+ def rename_table(name, new_name)
295
+ execute "ALTER TABLE #{name} RENAME TO #{new_name}"
296
+ end
297
+
298
+ def add_column(table_name, column_name, type, options = {})
299
+ execute("ALTER TABLE #{table_name} ADD #{column_name} #{type_to_sql(type, options[:limit])}")
300
+ execute("ALTER TABLE #{table_name} ALTER #{column_name} SET NOT NULL") if options[:null] == false
301
+ change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
302
+ end
303
+
304
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
305
+ begin
306
+ execute "ALTER TABLE #{table_name} ALTER #{column_name} TYPE #{type_to_sql(type, options[:limit])}"
307
+ rescue ActiveRecord::StatementInvalid
308
+ # This is PG7, so we use a more arcane way of doing it.
309
+ begin_db_transaction
310
+ add_column(table_name, "#{column_name}_ar_tmp", type, options)
311
+ execute "UPDATE #{table_name} SET #{column_name}_ar_tmp = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})"
312
+ remove_column(table_name, column_name)
313
+ rename_column(table_name, "#{column_name}_ar_tmp", column_name)
314
+ commit_db_transaction
315
+ end
316
+ change_column_default(table_name, column_name, options[:default]) unless options[:default].nil?
317
+ end
318
+
319
+ def change_column_default(table_name, column_name, default) #:nodoc:
320
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT '#{default}'"
321
+ end
322
+
323
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
324
+ execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
325
+ end
326
+
327
+ def remove_index(table_name, options) #:nodoc:
328
+ execute "DROP INDEX #{index_name(table_name, options)}"
329
+ end
330
+
331
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
332
+ return super unless type.to_s == 'integer'
333
+
334
+ if limit.nil? || limit == 4
335
+ 'integer'
336
+ elsif limit < 4
337
+ 'smallint'
338
+ else
339
+ 'bigint'
340
+ end
341
+ end
342
+
343
+ def tables
344
+ @connection.tables(database_name, nil, nil, ["TABLE"])
345
+ end
346
+ end
347
+ end
@@ -0,0 +1,72 @@
1
+ module JdbcSpec
2
+ module MissingFunctionalityHelper
3
+ #Taken from SQLite adapter
4
+
5
+ def alter_table(table_name, options = {}) #:nodoc:
6
+ table_name = table_name.to_s.downcase
7
+ altered_table_name = "altered_#{table_name}"
8
+ caller = lambda {|definition| yield definition if block_given?}
9
+
10
+ transaction do
11
+ move_table(table_name, altered_table_name, options)
12
+ move_table(altered_table_name, table_name, &caller)
13
+ end
14
+ end
15
+
16
+ def move_table(from, to, options = {}, &block) #:nodoc:
17
+ copy_table(from, to, options, &block)
18
+ drop_table(from)
19
+ end
20
+
21
+ def copy_table(from, to, options = {}) #:nodoc:
22
+ create_table(to, options) do |@definition|
23
+ columns(from).each do |column|
24
+ column_name = options[:rename] ?
25
+ (options[:rename][column.name] ||
26
+ options[:rename][column.name.to_sym] ||
27
+ column.name) : column.name
28
+ column_name = column_name.to_s
29
+ @definition.column(column_name, column.type,
30
+ :limit => column.limit, :default => column.default,
31
+ :null => column.null)
32
+ end
33
+ @definition.primary_key(primary_key(from))
34
+ yield @definition if block_given?
35
+ end
36
+
37
+ copy_table_indexes(from, to)
38
+ copy_table_contents(from, to,
39
+ @definition.columns,
40
+ options[:rename] || {})
41
+ end
42
+
43
+ def copy_table_indexes(from, to) #:nodoc:
44
+ indexes(from).each do |index|
45
+ name = index.name.downcase
46
+ if to == "altered_#{from}"
47
+ name = "temp_#{name}"
48
+ elsif from == "altered_#{to}"
49
+ name = name[5..-1]
50
+ end
51
+
52
+ # index name can't be the same
53
+ opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
54
+ opts[:unique] = true if index.unique
55
+ add_index(to, index.columns, opts)
56
+ end
57
+ end
58
+
59
+ def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
60
+ column_mappings = Hash[*columns.map {|col| [col.name, col.name]}.flatten]
61
+ rename.inject(column_mappings) {|map, a| map[a.last] = a.first; map}
62
+ from_columns = columns(from).collect {|col| col.name}
63
+ columns = columns.find_all{|col| from_columns.include?(column_mappings[col.name])}
64
+ execute("SELECT * FROM #{from}").each do |row|
65
+ sql = "INSERT INTO #{to} ("+columns.map(&:name)*','+") VALUES ("
66
+ sql << columns.map {|col| quote(row[column_mappings[col.name]],col)} * ', '
67
+ sql << ')'
68
+ execute sql
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ module JdbcAdapter
2
+ module Version
3
+ VERSION = "0.6"
4
+ end
5
+ end
@@ -0,0 +1,72 @@
1
+
2
+ # Task redefine code from public domain
3
+ module Rake
4
+ module TaskManager
5
+ def redefine_task(task_class, args, &block)
6
+ task_name, deps = resolve_args(args)
7
+ task_name = task_class.scope_name(@scope, task_name)
8
+ deps = [deps] unless deps.respond_to?(:to_ary)
9
+ deps = deps.collect {|d| d.to_s }
10
+ task = @tasks[task_name.to_s] = task_class.new(task_name, self)
11
+ task.application = self
12
+ task.add_comment(@last_comment)
13
+ @last_comment = nil
14
+ task.enhance(deps, &block)
15
+ task
16
+ end
17
+ end
18
+ class Task
19
+ class << self
20
+ def redefine_task(args, &block)
21
+ Rake.application.redefine_task(self, args, &block)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def redefine_task(args, &block)
28
+ Rake::Task.redefine_task(args, &block)
29
+ end
30
+
31
+ if RUBY_PLATFORM =~ /java/
32
+ namespace :db do
33
+ redefine_task :drop => :environment do
34
+ begin
35
+ config = ActiveRecord::Base.configurations[environment_name]
36
+ ActiveRecord::Base.establish_connection(config)
37
+ db = ActiveRecord::Base.connection.database_name
38
+ ActiveRecord::Base.connection.recreate_database(db)
39
+ rescue
40
+ end
41
+ end
42
+
43
+ namespace :structure do
44
+ redefine_task :dump => :environment do
45
+ abcs = ActiveRecord::Base.configurations
46
+ ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
47
+ File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
48
+ if ActiveRecord::Base.connection.supports_migrations?
49
+ File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
50
+ end
51
+ end
52
+ end
53
+ namespace :test do
54
+ redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
55
+ abcs = ActiveRecord::Base.configurations
56
+ ActiveRecord::Base.establish_connection(:test)
57
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
58
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
59
+ ActiveRecord::Base.connection.execute(ddl)
60
+ end
61
+ end
62
+
63
+ redefine_task :purge => :environment do
64
+ abcs = ActiveRecord::Base.configurations
65
+ ActiveRecord::Base.establish_connection(:test)
66
+ db = ActiveRecord::Base.connection.database_name
67
+ ActiveRecord::Base.connection.recreate_database(db)
68
+ end
69
+ end
70
+ end
71
+ end
72
+