ActiveRecord-JDBC 0.3.1 → 0.4

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/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.4
2
+
3
+ - Release coincides with JRuby 1.0 release
4
+ - Shoring up PostgreSQL (courtesy Dudley Flanders) and HSQL (courtesy Matthew Williams)
5
+ - Fix timestamps on Oracle to use DATE (as everything else)
6
+ - Derby fixes: Fix for open result set issue, better structure dump, quoting, column type changing
7
+ - Sybase type recognition fix (courtesy Dean Mao)
8
+
1
9
  == 0.3.1
2
10
 
3
11
  * Derby critical fixes shortly after 0.3
data/Manifest.txt CHANGED
@@ -26,6 +26,7 @@ test/db/jndi_config.rb
26
26
  test/db/logger.rb
27
27
  test/db/mysql.rb
28
28
  test/db/postgres.rb
29
+ test/derby_multibyte_test.rb
29
30
  test/derby_simple_test.rb
30
31
  test/h2_simple_test.rb
31
32
  test/hsqldb_simple_test.rb
@@ -45,3 +46,4 @@ test/models/entry.rb
45
46
  test/mysql_simple_test.rb
46
47
  test/postgres_simple_test.rb
47
48
  test/simple.rb
49
+ lib/tasks/jdbc_databases.rake
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
3
 
4
- task :default => :test
4
+ task :default => [:java_compile, :test]
5
5
 
6
6
  def java_classpath_arg # myriad of ways to discover JRuby classpath
7
7
  begin
@@ -40,13 +40,13 @@ end
40
40
  desc "Run AR-JDBC tests"
41
41
  if RUBY_PLATFORM =~ /java/
42
42
  # TODO: add more databases into the standard tests here.
43
- task :test => [:java_compile, :test_mysql, :test_derby]
43
+ task :test => [:test_mysql, :test_derby, :test_hsqldb]
44
44
  else
45
45
  task :test => [:test_mysql]
46
46
  end
47
47
 
48
48
  Rake::TestTask.new(:test_mysql) do |t|
49
- t.test_files = FileList['test/mysql_simple_test.rb']
49
+ t.test_files = FileList['test/mysql_*_test.rb']
50
50
  t.libs << 'test'
51
51
  end
52
52
 
@@ -56,13 +56,13 @@ Rake::TestTask.new(:test_hsqldb) do |t|
56
56
  end
57
57
 
58
58
  Rake::TestTask.new(:test_derby) do |t|
59
- t.test_files = FileList['test/derby_simple_test.rb',
59
+ t.test_files = FileList['test/derby_*_test.rb',
60
60
  'test/activerecord/connection_adapters/type_conversion_test.rb']
61
61
  t.libs << 'test'
62
62
  end
63
63
 
64
64
  Rake::TestTask.new(:test_postgresql) do |t|
65
- t.test_files = FileList['test/postgres_simple_test.rb']
65
+ t.test_files = FileList['test/postgres_*_test.rb']
66
66
  t.libs << 'test'
67
67
  end
68
68
 
@@ -75,7 +75,7 @@ end
75
75
 
76
76
  begin
77
77
  MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
78
- "Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter_internal.jar", "test/**/*.rb"]
78
+ "Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter_internal.jar", "test/**/*.rb", "lib/**/*.rake"]
79
79
 
80
80
  file "Manifest.txt" => :manifest
81
81
  task :manifest do
@@ -84,16 +84,15 @@ begin
84
84
  Rake::Task['manifest'].invoke # Always regen manifest, so Hoe has up-to-date list of files
85
85
 
86
86
  require 'hoe'
87
- Hoe.new("ActiveRecord-JDBC", "0.3.1") do |p|
87
+ Hoe.new("ActiveRecord-JDBC", "0.4") do |p|
88
88
  p.rubyforge_name = "jruby-extras"
89
89
  p.url = "http://jruby-extras.rubyforge.org/ActiveRecord-JDBC"
90
90
  p.author = "Nick Sieger, Ola Bini and JRuby contributors"
91
- p.email = "nick@nicksieger.com, ola.bini@ki.se"
91
+ p.email = "nick@nicksieger.com, ola.bini@gmail.com"
92
92
  p.summary = "JDBC adapter for ActiveRecord, for use within JRuby on Rails."
93
93
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
94
94
  p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
95
- p.extra_deps.reject!{|d| d.first == "hoe"}
96
- end
95
+ end.spec.dependencies.delete_if { |dep| dep.name == "hoe" }
97
96
  rescue LoadError
98
97
  puts "You really need Hoe installed to be able to package this gem"
99
98
  end
@@ -94,14 +94,16 @@ module ActiveRecord
94
94
  lambda {|r| r['type_name'] =~ /^real$/i},
95
95
  lambda {|r| r['precision'] == '15'}],
96
96
  :datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
97
- lambda {|r| r['type_name'] =~ /^datetime/i},
98
- lambda {|r| r['type_name'] =~ /^timestamp$/i}],
97
+ lambda {|r| r['type_name'] =~ /^datetime$/i},
98
+ lambda {|r| r['type_name'] =~ /^timestamp$/i},
99
+ lambda {|r| r['type_name'] =~ /^date/i}],
99
100
  :timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
100
101
  lambda {|r| r['type_name'] =~ /^timestamp$/i},
101
- lambda {|r| r['type_name'] =~ /^datetime/i} ],
102
+ lambda {|r| r['type_name'] =~ /^datetime/i},
103
+ lambda {|r| r['type_name'] =~ /^date/i}],
102
104
  :time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
103
105
  lambda {|r| r['type_name'] =~ /^time$/i},
104
- lambda {|r| r['type_name'] =~ /^datetime$/i}],
106
+ lambda {|r| r['type_name'] =~ /^date/i}],
105
107
  :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
106
108
  lambda {|r| r['type_name'] =~ /^date$/i}],
107
109
  :binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'].to_i)},
@@ -118,6 +120,7 @@ module ActiveRecord
118
120
 
119
121
  def initialize(types)
120
122
  @types = types
123
+ @types.each {|t| t['type_name'] ||= t['local_type_name']} # Sybase driver seems to want 'local_type_name'
121
124
  end
122
125
 
123
126
  def choose_best_types
@@ -139,7 +142,7 @@ module ActiveRecord
139
142
  return new_types.first if new_types.length == 1
140
143
  types = new_types if new_types.length > 0
141
144
  end
142
- raise "unable to choose type from: #{types.collect{|t| [t['type_name'],t]}.inspect} for #{ar_type}"
145
+ raise "unable to choose type for #{ar_type} from:\n#{types.collect{|t| t['type_name']}.inspect}"
143
146
  end
144
147
  end
145
148
 
@@ -193,7 +196,7 @@ module ActiveRecord
193
196
  end
194
197
 
195
198
  class JdbcConnection
196
- attr_reader :adapter
199
+ attr_reader :adapter, :connection
197
200
 
198
201
  def initialize(config)
199
202
  @config = config.symbolize_keys!
@@ -410,10 +413,10 @@ module ActiveRecord
410
413
  def _execute(sql, name = nil)
411
414
  log_no_bench(sql, name) do
412
415
  case sql.strip
413
- when /^(select|show)/i:
414
- @connection.execute_query(sql)
415
416
  when /^insert/i:
416
- @connection.execute_insert(sql)
417
+ @connection.execute_insert(sql)
418
+ when /^\(?\s*(select|show)/i:
419
+ @connection.execute_query(sql)
417
420
  else
418
421
  @connection.execute_update(sql)
419
422
  end
@@ -437,6 +440,10 @@ module ActiveRecord
437
440
  @connection.tables
438
441
  end
439
442
 
443
+ def indexes(table_name)
444
+ @connection.indexes(table_name)
445
+ end
446
+
440
447
  def begin_db_transaction
441
448
  @connection.begin
442
449
  end
@@ -2,21 +2,55 @@ require 'jdbc_adapter/missing_functionality_helper'
2
2
 
3
3
  module JdbcSpec
4
4
  module Derby
5
+ def self.monkey_rails
6
+ unless @already_monkeyd
7
+ # Needed because Rails is broken wrt to quoting of
8
+ # some values. Most databases are nice about it,
9
+ # but not Derby. The real issue is that you can't
10
+ # compare a CHAR value to a NUMBER column.
11
+ ::ActiveRecord::Associations::ClassMethods.module_eval do
12
+ private
13
+
14
+ def select_limited_ids_list(options, join_dependency)
15
+ connection.select_all(
16
+ construct_finder_sql_for_association_limiting(options, join_dependency),
17
+ "#{name} Load IDs For Limited Eager Loading"
18
+ ).collect { |row| connection.quote(row[primary_key], columns_hash[primary_key]) }.join(", ")
19
+ end
20
+ end
21
+
22
+ @already_monkeyd = true
23
+ end
24
+ end
25
+
26
+ def self.extended(*args)
27
+ monkey_rails
28
+ end
29
+
30
+ def self.included(*args)
31
+ monkey_rails
32
+ end
33
+
5
34
  module Column
6
35
  def type_cast(value)
7
36
  return nil if value.nil? || value =~ /^\s*null\s*$/i
8
37
  case type
9
38
  when :string then value
39
+ when :text then value
10
40
  when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
11
41
  when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
42
+ when :decimal then self.class.value_to_decimal(value)
12
43
  when :float then value.to_f
13
44
  when :datetime then cast_to_date_or_time(value)
45
+ when :date then self.class.string_to_date(value)
14
46
  when :timestamp then cast_to_time(value)
15
47
  when :binary then value.scan(/[0-9A-Fa-f]{2}/).collect {|v| v.to_i(16)}.pack("C*")
16
48
  when :time then cast_to_time(value)
49
+ when :boolean then self.class.value_to_boolean(value)
17
50
  else value
18
51
  end
19
52
  end
53
+
20
54
  def cast_to_date_or_time(value)
21
55
  return value if value.is_a? Date
22
56
  return nil if value.blank?
@@ -37,6 +71,7 @@ module JdbcSpec
37
71
 
38
72
  def simplified_type(field_type)
39
73
  return :boolean if field_type =~ /smallint/i
74
+ return :float if field_type =~ /real/i
40
75
  super
41
76
  end
42
77
  end
@@ -46,6 +81,7 @@ module JdbcSpec
46
81
  def modify_types(tp)
47
82
  tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
48
83
  tp[:integer][:limit] = nil
84
+ tp[:string][:limit] = 256
49
85
  tp[:boolean] = {:name => "smallint"}
50
86
  tp
51
87
  end
@@ -72,8 +108,8 @@ module JdbcSpec
72
108
 
73
109
  # Set the sequence to the max value of the table's column.
74
110
  def reset_sequence!(table, column, sequence = nil)
75
- mpk = select_value("SELECT MAX(#{column}) FROM #{table}")
76
- execute("ALTER TABLE #{table} ALTER COLUMN #{column} RESTART WITH #{mpk.to_i + 1}")
111
+ mpk = select_value("SELECT MAX(#{quote_column_name column}) FROM #{table}")
112
+ execute("ALTER TABLE #{table} ALTER COLUMN #{quote_column_name column} RESTART WITH #{mpk.to_i + 1}")
77
113
  end
78
114
 
79
115
  def reset_pk_sequence!(table, pk = nil, sequence = nil)
@@ -88,7 +124,9 @@ module JdbcSpec
88
124
  def _execute(sql, name = nil)
89
125
  log_no_bench(sql, name) do
90
126
  case sql.strip
91
- when /^(select|show)/i:
127
+ when /^insert/i:
128
+ @connection.execute_insert(sql)
129
+ when /^\(?\s*(select|show)/i:
92
130
  @offset ||= 0
93
131
  if !@limit || @limit == -1
94
132
  range = @offset..-1
@@ -98,8 +136,6 @@ module JdbcSpec
98
136
  max = @offset+@limit+1
99
137
  end
100
138
  @connection.execute_query(sql,max)[range] || []
101
- when /^insert/i:
102
- @connection.execute_insert(sql)
103
139
  else
104
140
  @connection.execute_update(sql)
105
141
  end
@@ -125,7 +161,7 @@ module JdbcSpec
125
161
  COLUMN_TYPE_STMT = "SELECT COLUMNDATATYPE, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
126
162
 
127
163
  AUTO_INC_STMT = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = '%s' AND COLUMNNAME = '%s'"
128
-
164
+ AUTO_INC_STMT2 = "SELECT AUTOINCREMENTSTART, AUTOINCREMENTINC, COLUMNNAME, REFERENCEID, COLUMNDEFAULT FROM SYS.SYSCOLUMNS WHERE REFERENCEID = (SELECT T.TABLEID FROM SYS.SYSTABLES T WHERE T.TABLENAME = '%s') AND COLUMNNAME = '%s'"
129
165
 
130
166
  def add_quotes(name)
131
167
  return name unless name
@@ -160,6 +196,43 @@ module JdbcSpec
160
196
  end
161
197
  false
162
198
  end
199
+
200
+ def reinstate_auto_increment(name, refid, coldef)
201
+ stmt = AUTO_INC_STMT % [refid, strip_quotes(name)]
202
+ data = execute(stmt).first
203
+ if data
204
+ start = data['autoincrementstart']
205
+ if start
206
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
207
+ coldef << "AS IDENTITY (START WITH "
208
+ coldef << start
209
+ coldef << ", INCREMENT BY "
210
+ coldef << data['autoincrementinc']
211
+ coldef << ")"
212
+ return true
213
+ end
214
+ end
215
+ false
216
+ end
217
+
218
+ def auto_increment_stmt(tname, cname)
219
+ stmt = AUTO_INC_STMT2 % [tname, strip_quotes(cname)]
220
+ data = execute(stmt).first
221
+ if data
222
+ start = data['autoincrementstart']
223
+ if start
224
+ coldef = ""
225
+ coldef << " GENERATED " << (data['columndefault'].nil? ? "ALWAYS" : "BY DEFAULT ")
226
+ coldef << "AS IDENTITY (START WITH "
227
+ coldef << start
228
+ coldef << ", INCREMENT BY "
229
+ coldef << data['autoincrementinc']
230
+ coldef << ")"
231
+ return coldef
232
+ end
233
+ end
234
+ ""
235
+ end
163
236
 
164
237
  def create_column(name, refid, colno)
165
238
  stmt = COLUMN_TYPE_STMT % [refid, strip_quotes(name)]
@@ -176,36 +249,57 @@ module JdbcSpec
176
249
  coldef
177
250
  end
178
251
 
252
+ SIZEABLE = %w(VARCHAR CLOB BLOB)
253
+
179
254
  def structure_dump #:nodoc:
180
- data = ""
181
- execute("select tablename, tableid from sys.systables where schemaid not in (select schemaid from sys.sysschemas where schemaname LIKE 'SYS%')").each do |tbl|
182
- tid = tbl["tableid"]
183
- tname = tbl["tablename"]
184
- data << "CREATE TABLE #{tname} (\n"
255
+ definition=""
256
+ rs = @connection.connection.meta_data.getTables(nil,nil,nil,["TABLE"].to_java(:string))
257
+ while rs.next
258
+ tname = rs.getString(3)
259
+ definition << "CREATE TABLE #{tname} (\n"
260
+ rs2 = @connection.connection.meta_data.getColumns(nil,nil,tname,nil)
185
261
  first_col = true
186
- execute(COLUMN_INFO_STMT % tid).each do |col|
187
- col_name = add_quotes(col['columnname']);
188
- create_col_string = create_column(col_name, col['referenceid'],col['columnnumber'].to_i)
262
+ while rs2.next
263
+ col_name = add_quotes(rs2.getString(4));
264
+ default = ""
265
+ d1 = rs2.getString(13)
266
+ if d1 =~ /^GENERATED_/
267
+ default = auto_increment_stmt(tname, col_name)
268
+ elsif d1
269
+ default = " DEFAULT #{d1}"
270
+ end
271
+
272
+ type = rs2.getString(6)
273
+ col_size = rs2.getString(7)
274
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
275
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
276
+ " " +
277
+ type +
278
+ (SIZEABLE.include?(type) ? "(#{col_size})" : "") +
279
+ nulling +
280
+ default
189
281
  if !first_col
190
282
  create_col_string = ",\n #{create_col_string}"
191
283
  else
192
284
  create_col_string = " #{create_col_string}"
193
285
  end
194
-
195
- data << create_col_string
196
-
286
+
287
+ definition << create_col_string
288
+
197
289
  first_col = false
198
290
  end
199
- data << ");\n\n"
291
+ definition << ");\n\n"
200
292
  end
201
- data
293
+ definition
202
294
  end
203
295
 
204
296
  # Support for removing columns added via derby bug issue:
205
297
  # https://issues.apache.org/jira/browse/DERBY-1489
206
298
  #
207
- # This feature has not made it into a formal release and is not in Java 6. We will
208
- # need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
299
+ # This feature has not made it into a formal release and is not in Java 6.
300
+ # If the normal strategy fails we fall back on a strategy by creating a new
301
+ # table without the new column and there after moving the data to the new
302
+ #
209
303
  def remove_column(table_name, column_name)
210
304
  begin
211
305
  execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name} RESTRICT"
@@ -213,39 +307,46 @@ module JdbcSpec
213
307
  alter_table(table_name) do |definition|
214
308
  definition.columns.delete(definition[column_name])
215
309
  end
216
- # raise NotImplementedError, "remove_column is not support on this Derby version"
217
310
  end
218
311
  end
219
312
 
220
313
  # Notes about changing in Derby:
221
314
  # http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
222
- # Derby cannot: Change the column type or decrease the precision of an existing type, but
223
- # can increase the types precision only if it is a VARCHAR.
224
315
  #
225
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
226
- # Derby can't change the datatype or size unless the type is varchar
227
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}" if type == :string
228
- if options.include? :null
316
+ # We support changing columns using the strategy outlined in:
317
+ # https://issues.apache.org/jira/browse/DERBY-1515
318
+ #
319
+ # This feature has not made it into a formal release and is not in Java 6. We will
320
+ # need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
321
+ def change_column(table_name, column_name, type, options = {})
322
+ # null/not nulling is easy, handle that separately
323
+ if options.include?(:null)
229
324
  # This seems to only work with 10.2 of Derby
230
- if options[:null] == false
325
+ if options.delete(:null) == false
231
326
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NOT NULL"
232
327
  else
233
328
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} NULL"
234
329
  end
235
330
  end
236
- end
237
331
 
238
- # There seems to be more than one thing wrong with
239
- # changing defaults for VARCHAR columns right now... DERBY-2371
240
- # among others
241
- def change_column_default(table_name, column_name, default) #:nodoc:
242
- begin
243
- execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DEFAULT #{quote(default)}"
244
- rescue
245
- alter_table(table_name) do |definition|
246
- definition[column_name].default = default
332
+ # anything left to do?
333
+ unless options.empty?
334
+ begin
335
+ execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
336
+ rescue
337
+ transaction do
338
+ temp_new_column_name = "#{column_name}_newtype"
339
+ # 1) ALTER TABLE t ADD COLUMN c1_newtype NEWTYPE;
340
+ add_column table_name, temp_new_column_name, type, options
341
+ # 2) UPDATE t SET c1_newtype = c1;
342
+ execute "UPDATE #{table_name} SET #{temp_new_column_name} = CAST(#{column_name} AS #{type_to_sql(type, options[:limit])})"
343
+ # 3) ALTER TABLE t DROP COLUMN c1;
344
+ remove_column table_name, column_name
345
+ # 4) ALTER TABLE t RENAME COLUMN c1_newtype to c1;
346
+ rename_column table_name, temp_new_column_name, column_name
347
+ end
247
348
  end
248
- end
349
+ end
249
350
  end
250
351
 
251
352
  # Support for renaming columns:
@@ -268,15 +369,8 @@ module JdbcSpec
268
369
 
269
370
  def recreate_database(db_name)
270
371
  tables.each do |t|
271
- drop_table t rescue nil
372
+ drop_table t
272
373
  end
273
- end
274
-
275
- # For migrations, exclude the primary key index as recommended
276
- # by the HSQLDB docs. This is not a great test for primary key
277
- # index.
278
- def indexes(table_name)
279
- @connection.indexes(table_name)
280
374
  end
281
375
 
282
376
  def quote(value, column = nil) # :nodoc:
@@ -288,6 +382,8 @@ module JdbcSpec
288
382
  case column.type
289
383
  when :binary
290
384
  "CAST(x'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}' AS BLOB)"
385
+ when :text
386
+ "CAST('#{quote_string(value)}' AS CLOB)"
291
387
  when :string
292
388
  "'#{quote_string(value)}'"
293
389
  else
@@ -295,12 +391,23 @@ module JdbcSpec
295
391
  if vi.to_s == value
296
392
  value
297
393
  else
298
- "'#{quote_string(value)}'"
394
+ super
299
395
  end
300
396
  end
301
397
  else
302
398
  super
303
399
  end
400
+ when Float, Fixnum, Bignum
401
+ if column
402
+ case column.type
403
+ when :string
404
+ "'#{quote_string(value.to_s)}'"
405
+ else
406
+ super
407
+ end
408
+ else
409
+ super
410
+ end
304
411
  else super
305
412
  end
306
413
  end
@@ -313,6 +420,10 @@ module JdbcSpec
313
420
  def quote_column_name(name) #:nodoc:
314
421
  if /^references$/i =~ name
315
422
  %Q{"#{name.upcase}"}
423
+ elsif /[A-Z]/ =~ name && /[a-z]/ =~ name
424
+ %Q{"#{name}"}
425
+ elsif name =~ /\s/
426
+ %Q{"#{name.upcase}"}
316
427
  else
317
428
  name
318
429
  end
@@ -327,3 +438,4 @@ module JdbcSpec
327
438
  end
328
439
  end
329
440
  end
441
+
@@ -110,7 +110,9 @@ module JdbcSpec
110
110
  end
111
111
 
112
112
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
113
- execute(sql, name)
113
+ log_no_bench(sql,name) do
114
+ @connection.execute_update(sql)
115
+ end
114
116
  table = sql.split(" ", 4)[2]
115
117
  id_value || last_insert_id(table, nil)
116
118
  end
@@ -136,17 +138,7 @@ module JdbcSpec
136
138
  # system tables SYSTEM.*, but H2 seems to name them without
137
139
  # any kind of convention
138
140
  def tables
139
- @connection.tables do |result_row|
140
- result_row.get_string(ActiveRecord::ConnectionAdapters::Jdbc::TableMetaData::TABLE_TYPE) !~ /^SYSTEM TABLE$/i
141
- end
141
+ @connection.tables.select {|row| row.to_s !~ /^system_/i }
142
142
  end
143
-
144
- # For migrations, exclude the primary key index as recommended
145
- # by the HSQLDB docs. This is not a great test for primary key
146
- # index.
147
- def indexes(table_name, name = nil)
148
- @connection.indexes(table_name.to_s)
149
- end
150
-
151
143
  end
152
144
  end
@@ -58,11 +58,6 @@ module JdbcSpec
58
58
  def quote_column_name(name) #:nodoc:
59
59
  "`#{name}`"
60
60
  end
61
-
62
- # from active_record/vendor/mysql.rb
63
- def quote_string(str) #:nodoc:
64
- @connection.mysql_quote_string(str)
65
- end
66
61
 
67
62
  def quoted_true
68
63
  "1"
@@ -104,10 +99,6 @@ module JdbcSpec
104
99
  select_one("SELECT DATABASE() as db")["db"]
105
100
  end
106
101
 
107
- def indexes(table_name, name = nil)#:nodoc:
108
- @connection.indexes(table_name)
109
- end
110
-
111
102
  def create_table(name, options = {}) #:nodoc:
112
103
  super(name, {:options => "ENGINE=InnoDB"}.merge(options))
113
104
  end
@@ -10,6 +10,8 @@ module JdbcSpec
10
10
  when :float then value.to_f
11
11
  when :datetime then cast_to_date_or_time(value)
12
12
  when :time then cast_to_time(value)
13
+ when :decimal then self.class.value_to_decimal(value)
14
+ when :boolean then self.class.value_to_boolean(value)
13
15
  else value
14
16
  end
15
17
  end
@@ -57,6 +57,24 @@ module JdbcSpec
57
57
  default_seq || "#{table_name}_#{pk || default_pk || 'id'}_seq"
58
58
  end
59
59
 
60
+ # Resets sequence to the max value of the table's pk if present.
61
+ def reset_pk_sequence!(table, pk = nil, sequence = nil)
62
+ unless pk and sequence
63
+ default_pk, default_sequence = pk_and_sequence_for(table)
64
+ pk ||= default_pk
65
+ sequence ||= default_sequence
66
+ end
67
+ if pk
68
+ if sequence
69
+ select_value <<-end_sql, 'Reset sequence'
70
+ SELECT setval('#{sequence}', (SELECT COALESCE(MAX(#{pk})+(SELECT increment_by FROM #{sequence}), (SELECT min_value FROM #{sequence})) FROM #{table}), false)
71
+ end_sql
72
+ else
73
+ @logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
74
+ end
75
+ end
76
+ end
77
+
60
78
  # Find a table's primary key and sequence.
61
79
  def pk_and_sequence_for(table)
62
80
  # First try looking for a sequence with a dependency on the
@@ -185,5 +203,9 @@ module JdbcSpec
185
203
  'bigint'
186
204
  end
187
205
  end
206
+
207
+ def tables
208
+ @connection.tables(database_name, nil, nil, ["TABLE"])
209
+ end
188
210
  end
189
211
  end
@@ -3,12 +3,12 @@ module JdbcSpec
3
3
  #Taken from SQLite adapter
4
4
 
5
5
  def alter_table(table_name, options = {}) #:nodoc:
6
- table_name = table_name.downcase
6
+ table_name = table_name.to_s.downcase
7
7
  altered_table_name = "altered_#{table_name}"
8
8
  caller = lambda {|definition| yield definition if block_given?}
9
9
 
10
10
  transaction do
11
- move_table(table_name, altered_table_name)
11
+ move_table(table_name, altered_table_name, options)
12
12
  move_table(altered_table_name, table_name, &caller)
13
13
  end
14
14
  end
@@ -25,7 +25,7 @@ module JdbcSpec
25
25
  (options[:rename][column.name] ||
26
26
  options[:rename][column.name.to_sym] ||
27
27
  column.name) : column.name
28
-
28
+ column_name = column_name.to_s
29
29
  @definition.column(column_name, column.type,
30
30
  :limit => column.limit, :default => column.default,
31
31
  :null => column.null)
@@ -36,7 +36,7 @@ module JdbcSpec
36
36
 
37
37
  copy_table_indexes(from, to)
38
38
  copy_table_contents(from, to,
39
- @definition.columns.map {|column| column.name},
39
+ @definition.columns,
40
40
  options[:rename] || {})
41
41
  end
42
42
 
@@ -57,13 +57,13 @@ module JdbcSpec
57
57
  end
58
58
 
59
59
  def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
60
- column_mappings = Hash[*columns.map {|name| [name, name]}.flatten]
60
+ column_mappings = Hash[*columns.map {|col| [col.name, col.name]}.flatten]
61
61
  rename.inject(column_mappings) {|map, a| map[a.last] = a.first; map}
62
62
  from_columns = columns(from).collect {|col| col.name}
63
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
63
+ columns = columns.find_all{|col| from_columns.include?(column_mappings[col.name])}
64
64
  execute("SELECT * FROM #{from}").each do |row|
65
- sql = "INSERT INTO #{to} ("+columns*','+") VALUES ("
66
- sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
65
+ sql = "INSERT INTO #{to} ("+columns.map(&:name)*','+") VALUES ("
66
+ sql << columns.map {|col| quote(row[column_mappings[col.name]],col)} * ', '
67
67
  sql << ')'
68
68
  execute sql
69
69
  end
Binary file
@@ -0,0 +1,62 @@
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
+ namespace :structure do
34
+ redefine_task :dump => :environment do
35
+ abcs = ActiveRecord::Base.configurations
36
+ ActiveRecord::Base.establish_connection(abcs[RAILS_ENV])
37
+ File.open("db/#{RAILS_ENV}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
38
+ if ActiveRecord::Base.connection.supports_migrations?
39
+ File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
40
+ end
41
+ end
42
+ end
43
+ namespace :test do
44
+ redefine_task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
45
+ abcs = ActiveRecord::Base.configurations
46
+ ActiveRecord::Base.establish_connection(:test)
47
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') if abcs["test"]["adapter"] =~ /mysql/i
48
+ IO.readlines("db/#{RAILS_ENV}_structure.sql").join.split(";\n\n").each do |ddl|
49
+ ActiveRecord::Base.connection.execute(ddl)
50
+ end
51
+ end
52
+
53
+ redefine_task :purge => :environment do
54
+ abcs = ActiveRecord::Base.configurations
55
+ ActiveRecord::Base.establish_connection(:test)
56
+ db = ActiveRecord::Base.connection.database_name
57
+ ActiveRecord::Base.connection.recreate_database(db)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
@@ -0,0 +1,12 @@
1
+ # To run this script, run the following in a mysql instance:
2
+ #
3
+ # drop database if exists weblog_development;
4
+ # create database weblog_development;
5
+ # grant all on weblog_development.* to blog@localhost;
6
+
7
+ require 'jdbc_common'
8
+ require 'db/derby'
9
+
10
+ class DerbyMultibyteTest < Test::Unit::TestCase
11
+ include MultibyteTestMethods
12
+ end
@@ -3,6 +3,7 @@
3
3
  # drop database if exists weblog_development;
4
4
  # create database weblog_development;
5
5
  # grant all on weblog_development.* to blog@localhost;
6
+ # flush privileges;
6
7
 
7
8
  require 'jdbc_common'
8
9
  require 'db/mysql'
data/test/simple.rb CHANGED
@@ -114,3 +114,40 @@ module SimpleTestMethods
114
114
  end
115
115
 
116
116
  end
117
+
118
+ class ActiveRecord::Base
119
+ cattr_accessor :defined_connections
120
+ end
121
+
122
+ module MultibyteTestMethods
123
+ include MigrationSetup
124
+
125
+ def setup
126
+ super
127
+ config = ActiveRecord::Base.defined_connections["ActiveRecord::Base"].config
128
+ props = java.util.Properties.new
129
+ props.setProperty("user", config[:username])
130
+ props.setProperty("password", config[:password])
131
+ @java_con = java.sql.DriverManager.getConnection(config[:url], props)
132
+ @java_con.setAutoCommit(true)
133
+ end
134
+
135
+ def teardown
136
+ @java_con.close
137
+ super
138
+ end
139
+
140
+ def test_select_multibyte_string
141
+ @java_con.createStatement().execute("insert into entries (title) values ('テスト')")
142
+ entry = Entry.find(:first)
143
+ assert_equal "テスト", entry.title
144
+ assert_equal entry, Entry.find_by_title("テスト")
145
+ end
146
+
147
+ def test_update_multibyte_string
148
+ Entry.create!(:title => "テスト")
149
+ rs = @java_con.createStatement().executeQuery("select title from entries")
150
+ assert rs.next
151
+ assert_equal "テスト", rs.getString(1)
152
+ end
153
+ end
metadata CHANGED
@@ -3,12 +3,12 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: ActiveRecord-JDBC
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.1
7
- date: 2007-05-07 00:00:00 -05:00
6
+ version: "0.4"
7
+ date: 2007-06-07 00:00:00 -07:00
8
8
  summary: JDBC adapter for ActiveRecord, for use within JRuby on Rails.
9
9
  require_paths:
10
10
  - lib
11
- email: nick@nicksieger.com, ola.bini@ki.se
11
+ email: nick@nicksieger.com, ola.bini@gmail.com
12
12
  homepage: http://jruby-extras.rubyforge.org/ActiveRecord-JDBC
13
13
  rubyforge_project: jruby-extras
14
14
  description: ActiveRecord-JDBC is a database adapter for Rails' ActiveRecord component that can be used with JRuby[http://www.jruby.org/]. It allows use of virtually any JDBC-compliant database with your JRuby on Rails application.
@@ -57,6 +57,7 @@ files:
57
57
  - test/db/logger.rb
58
58
  - test/db/mysql.rb
59
59
  - test/db/postgres.rb
60
+ - test/derby_multibyte_test.rb
60
61
  - test/derby_simple_test.rb
61
62
  - test/h2_simple_test.rb
62
63
  - test/hsqldb_simple_test.rb
@@ -76,12 +77,16 @@ files:
76
77
  - test/mysql_simple_test.rb
77
78
  - test/postgres_simple_test.rb
78
79
  - test/simple.rb
80
+ - lib/tasks/jdbc_databases.rake
79
81
  test_files: []
80
82
 
81
- rdoc_options: []
82
-
83
- extra_rdoc_files: []
84
-
83
+ rdoc_options:
84
+ - --main
85
+ - README.txt
86
+ extra_rdoc_files:
87
+ - History.txt
88
+ - Manifest.txt
89
+ - README.txt
85
90
  executables: []
86
91
 
87
92
  extensions: []