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 +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: []
|