activerecord-jdbc-adapter 0.6

Sign up to get free protection for your applications and to get access to all the features.
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
+