ActiveRecord-JDBC 0.3.1 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +2 -0
- data/Rakefile +9 -10
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +16 -9
- data/lib/jdbc_adapter/jdbc_derby.rb +161 -49
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +4 -12
- data/lib/jdbc_adapter/jdbc_mysql.rb +0 -9
- data/lib/jdbc_adapter/jdbc_oracle.rb +2 -0
- data/lib/jdbc_adapter/jdbc_postgre.rb +22 -0
- data/lib/jdbc_adapter/missing_functionality_helper.rb +8 -8
- data/lib/jdbc_adapter_internal.jar +0 -0
- data/lib/tasks/jdbc_databases.rake +62 -0
- data/test/derby_multibyte_test.rb +12 -0
- data/test/mysql_simple_test.rb +1 -0
- data/test/simple.rb +37 -0
- metadata +12 -7
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 => [:
|
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/
|
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/
|
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/
|
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.
|
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@
|
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
|
-
|
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
|
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'] =~ /^
|
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
|
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
|
-
|
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 /^
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
tname =
|
184
|
-
|
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
|
-
|
187
|
-
col_name = add_quotes(
|
188
|
-
|
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
|
-
|
196
|
-
|
286
|
+
|
287
|
+
definition << create_col_string
|
288
|
+
|
197
289
|
first_col = false
|
198
290
|
end
|
199
|
-
|
291
|
+
definition << ");\n\n"
|
200
292
|
end
|
201
|
-
|
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.
|
208
|
-
#
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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
|
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
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
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 {|
|
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
|
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
|
data/test/mysql_simple_test.rb
CHANGED
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.
|
7
|
-
date: 2007-
|
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@
|
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
|
-
|
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: []
|