activerecord-jdbc-adapter 0.9.0.1 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +31 -0
- data/Manifest.txt +7 -0
- data/README.txt +15 -2
- data/Rakefile +28 -30
- data/lib/active_record/connection_adapters/h2_adapter.rb +13 -1
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +78 -96
- data/lib/jdbc_adapter/jdbc.rake +15 -5
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +4 -4
- data/lib/jdbc_adapter/jdbc_db2.rb +5 -7
- data/lib/jdbc_adapter/jdbc_derby.rb +57 -30
- data/lib/jdbc_adapter/jdbc_firebird.rb +2 -2
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +53 -46
- data/lib/jdbc_adapter/jdbc_informix.rb +4 -5
- data/lib/jdbc_adapter/jdbc_mimer.rb +2 -2
- data/lib/jdbc_adapter/jdbc_mssql.rb +25 -23
- data/lib/jdbc_adapter/jdbc_mysql.rb +20 -22
- data/lib/jdbc_adapter/jdbc_oracle.rb +115 -117
- data/lib/jdbc_adapter/jdbc_postgre.rb +129 -59
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +149 -28
- data/lib/jdbc_adapter/jdbc_sybase.rb +13 -2
- data/lib/jdbc_adapter/missing_functionality_helper.rb +12 -3
- data/lib/jdbc_adapter/version.rb +1 -1
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +6 -1101
- data/src/java/jdbc_adapter/JdbcDerbySpec.java +26 -23
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +79 -28
- data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +35 -0
- data/src/java/jdbc_adapter/RubyJdbcConnection.java +1149 -0
- data/src/java/jdbc_adapter/SQLBlock.java +12 -3
- data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +1 -1
- data/test/db/derby.rb +0 -3
- data/test/db/h2.rb +0 -3
- data/test/db/hsqldb.rb +1 -4
- data/test/db/mysql.rb +1 -0
- data/test/db/oracle.rb +5 -0
- data/test/db/sqlite3.rb +7 -3
- data/test/derby_migration_test.rb +21 -0
- data/test/has_many_through.rb +11 -4
- data/test/jdbc_common.rb +13 -1
- data/test/models/data_types.rb +11 -1
- data/test/models/mixed_case.rb +20 -0
- data/test/mysql_multibyte_test.rb +4 -0
- data/test/oracle_simple_test.rb +1 -1
- data/test/postgres_mixed_case_test.rb +19 -0
- data/test/simple.rb +220 -41
- data/test/sqlite3_simple_test.rb +83 -0
- data/test/sybase_jtds_simple_test.rb +6 -0
- metadata +12 -10
Binary file
|
@@ -13,12 +13,12 @@ module ::JdbcSpec
|
|
13
13
|
module CacheDB
|
14
14
|
include TSqlMethods
|
15
15
|
|
16
|
-
def self.
|
17
|
-
|
16
|
+
def self.adapter_matcher(name, *)
|
17
|
+
name =~ /cache/i ? self : false
|
18
18
|
end
|
19
19
|
|
20
|
-
def self.
|
21
|
-
[ /cache/i, lambda { | cfg,
|
20
|
+
def self.column_selector
|
21
|
+
[ /cache/i, lambda { | cfg, col | col.extend( ::JdbcSpec::CacheDB::Column ) } ]
|
22
22
|
end
|
23
23
|
|
24
24
|
module Column
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module JdbcSpec
|
2
2
|
module DB2
|
3
|
-
def self.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
col.extend(::JdbcSpec::DB2::Column)
|
9
|
-
end }]
|
3
|
+
def self.adapter_matcher(name, config)
|
4
|
+
if name =~ /db2/i
|
5
|
+
return cfg[:url] =~ /^jdbc:derby:net:/ ? ::JdbcSpec::Derby : self
|
6
|
+
end
|
7
|
+
false
|
10
8
|
end
|
11
9
|
|
12
10
|
def self.adapter_selector
|
@@ -10,12 +10,12 @@ module ::JdbcSpec
|
|
10
10
|
end
|
11
11
|
|
12
12
|
module Derby
|
13
|
-
def self.
|
14
|
-
|
13
|
+
def self.adapter_matcher(name, *)
|
14
|
+
name =~ /derby/i ? self : false
|
15
15
|
end
|
16
16
|
|
17
|
-
def self.
|
18
|
-
[/derby/i, lambda {|cfg,
|
17
|
+
def self.column_selector
|
18
|
+
[/derby/i, lambda {|cfg,col| col.extend(::JdbcSpec::Derby::Column)}]
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.monkey_rails
|
@@ -48,37 +48,36 @@ module ::JdbcSpec
|
|
48
48
|
end
|
49
49
|
|
50
50
|
module Column
|
51
|
-
def value_to_binary(value)
|
52
|
-
value.scan(/[0-9A-Fa-f]{2}/).collect {|v| v.to_i(16)}.pack("C*")
|
53
|
-
end
|
54
|
-
|
55
|
-
def cast_to_date_or_time(value)
|
56
|
-
return value if value.is_a? Date
|
57
|
-
return nil if value.blank?
|
58
|
-
guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
|
59
|
-
end
|
60
|
-
|
61
|
-
def cast_to_time(value)
|
62
|
-
return value if value.is_a? Time
|
63
|
-
time_array = ParseDate.parsedate value
|
64
|
-
time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
|
65
|
-
Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
|
66
|
-
end
|
67
|
-
|
68
|
-
def guess_date_or_time(value)
|
69
|
-
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
70
|
-
Date.new(value.year, value.month, value.day) : value
|
71
|
-
end
|
72
|
-
|
73
51
|
def simplified_type(field_type)
|
74
52
|
return :boolean if field_type =~ /smallint/i
|
75
53
|
return :float if field_type =~ /real/i
|
76
54
|
super
|
77
55
|
end
|
56
|
+
|
57
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
58
|
+
def default_value(value)
|
59
|
+
# jdbc returns column default strings with actual single quotes around the value.
|
60
|
+
return $1 if value =~ /^'(.*)'$/
|
61
|
+
|
62
|
+
value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def adapter_name #:nodoc:
|
67
|
+
'Derby'
|
78
68
|
end
|
79
69
|
|
80
70
|
include JdbcSpec::MissingFunctionalityHelper
|
81
71
|
|
72
|
+
# Convert the speficied column type to a SQL string. In Derby, :integers cannot specify
|
73
|
+
# a limit.
|
74
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
75
|
+
return super unless type == :integer
|
76
|
+
|
77
|
+
native = native_database_types[type.to_s.downcase.to_sym]
|
78
|
+
native.is_a?(Hash) ? native[:name] : native
|
79
|
+
end
|
80
|
+
|
82
81
|
def modify_types(tp)
|
83
82
|
tp[:primary_key] = "int generated by default as identity NOT NULL PRIMARY KEY"
|
84
83
|
tp[:integer][:limit] = nil
|
@@ -100,8 +99,8 @@ module ::JdbcSpec
|
|
100
99
|
|
101
100
|
# Set the sequence to the max value of the table's column.
|
102
101
|
def reset_sequence!(table, column, sequence = nil)
|
103
|
-
mpk = select_value("SELECT MAX(#{quote_column_name
|
104
|
-
execute("ALTER TABLE #{table} ALTER COLUMN #{quote_column_name
|
102
|
+
mpk = select_value("SELECT MAX(#{quote_column_name(column)}) FROM #{quote_table_name(table)}")
|
103
|
+
execute("ALTER TABLE #{quote_table_name(table)} ALTER COLUMN #{quote_column_name(column)} RESTART WITH #{mpk.to_i + 1}")
|
105
104
|
end
|
106
105
|
|
107
106
|
def reset_pk_sequence!(table, pk = nil, sequence = nil)
|
@@ -216,6 +215,19 @@ module ::JdbcSpec
|
|
216
215
|
end
|
217
216
|
end
|
218
217
|
|
218
|
+
def execute(sql, name = nil)
|
219
|
+
if sql =~ /^\s*(UPDATE|INSERT)/i
|
220
|
+
i = sql =~ /\swhere\s/im
|
221
|
+
if i
|
222
|
+
sql[i..-1] = sql[i..-1].gsub(/!=\s*NULL/, 'IS NOT NULL').gsub(/=\sNULL/i, 'IS NULL')
|
223
|
+
end
|
224
|
+
else
|
225
|
+
sql.gsub!(/= NULL/i, 'IS NULL')
|
226
|
+
end
|
227
|
+
super
|
228
|
+
end
|
229
|
+
|
230
|
+
|
219
231
|
# I don't think this method is ever called ??? (stepheneb)
|
220
232
|
def create_column(name, refid, colno)
|
221
233
|
stmt = COLUMN_TYPE_STMT % [refid, strip_quotes(name)]
|
@@ -350,6 +362,14 @@ module ::JdbcSpec
|
|
350
362
|
@connection.primary_keys table_name.to_s.upcase
|
351
363
|
end
|
352
364
|
|
365
|
+
def columns(table_name, name=nil)
|
366
|
+
@connection.columns_internal(table_name.to_s, name, derby_schema)
|
367
|
+
end
|
368
|
+
|
369
|
+
def tables
|
370
|
+
@connection.tables(nil, derby_schema)
|
371
|
+
end
|
372
|
+
|
353
373
|
def recreate_database(db_name)
|
354
374
|
tables.each do |t|
|
355
375
|
drop_table t
|
@@ -359,11 +379,11 @@ module ::JdbcSpec
|
|
359
379
|
# For DDL it appears you can quote "" column names, but in queries (like insert it errors out?)
|
360
380
|
def quote_column_name(name) #:nodoc:
|
361
381
|
name = name.to_s
|
362
|
-
if /^references$/i =~ name
|
382
|
+
if /^(references|integer|key|group|year)$/i =~ name
|
363
383
|
%Q{"#{name.upcase}"}
|
364
384
|
elsif /[A-Z]/ =~ name && /[a-z]/ =~ name
|
365
385
|
%Q{"#{name}"}
|
366
|
-
elsif name =~
|
386
|
+
elsif name =~ /[\s-]/
|
367
387
|
%Q{"#{name.upcase}"}
|
368
388
|
elsif name =~ /^[_\d]/
|
369
389
|
%Q{"#{name.upcase}"}
|
@@ -379,6 +399,13 @@ module ::JdbcSpec
|
|
379
399
|
def quoted_false
|
380
400
|
'0'
|
381
401
|
end
|
402
|
+
|
403
|
+
private
|
404
|
+
# Derby appears to define schemas using the username
|
405
|
+
def derby_schema
|
406
|
+
@config[:username].to_s
|
407
|
+
end
|
382
408
|
end
|
383
409
|
end
|
384
410
|
|
411
|
+
|
@@ -14,56 +14,22 @@ module ::JdbcSpec
|
|
14
14
|
end
|
15
15
|
|
16
16
|
module HSQLDB
|
17
|
-
def self.
|
18
|
-
|
17
|
+
def self.adapter_matcher(name, *)
|
18
|
+
name =~ /hsqldb/i ? self : false
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.
|
22
|
-
[/hsqldb|\.h2\./i, lambda
|
23
|
-
adapt.extend(::JdbcSpec::HSQLDB)
|
24
|
-
def adapt.h2_adapter; true; end if cfg[:driver] =~ /\.h2\./
|
25
|
-
end]
|
21
|
+
def self.column_selector
|
22
|
+
[/hsqldb|\.h2\./i, lambda {|cfg,col| col.extend(::JdbcSpec::HSQLDB::Column)}]
|
26
23
|
end
|
27
24
|
|
28
25
|
module Column
|
29
|
-
def type_cast(value)
|
30
|
-
return nil if value.nil? || value =~ /^\s*null\s*$/i
|
31
|
-
case type
|
32
|
-
when :string then value
|
33
|
-
when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
34
|
-
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
35
|
-
when :float then value.to_f
|
36
|
-
when :datetime then cast_to_date_or_time(value)
|
37
|
-
when :timestamp then cast_to_time(value)
|
38
|
-
when :binary then value.scan(/[0-9A-Fa-f]{2}/).collect {|v| v.to_i(16)}.pack("C*")
|
39
|
-
when :time then cast_to_time(value)
|
40
|
-
else value
|
41
|
-
end
|
42
|
-
end
|
43
|
-
def cast_to_date_or_time(value)
|
44
|
-
return value if value.is_a? Date
|
45
|
-
return nil if value.blank?
|
46
|
-
guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
|
47
|
-
end
|
48
|
-
|
49
|
-
def cast_to_time(value)
|
50
|
-
return value if value.is_a? Time
|
51
|
-
time_array = ParseDate.parsedate value
|
52
|
-
time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
|
53
|
-
Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
|
54
|
-
end
|
55
|
-
|
56
|
-
def guess_date_or_time(value)
|
57
|
-
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
58
|
-
Date.new(value.year, value.month, value.day) : value
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
26
|
private
|
63
27
|
def simplified_type(field_type)
|
64
28
|
case field_type
|
65
29
|
when /longvarchar/i
|
66
30
|
:text
|
31
|
+
when /tinyint/i
|
32
|
+
:boolean
|
67
33
|
else
|
68
34
|
super(field_type)
|
69
35
|
end
|
@@ -76,6 +42,18 @@ module ::JdbcSpec
|
|
76
42
|
return nil if sql_type =~ /\(0\)/
|
77
43
|
super
|
78
44
|
end
|
45
|
+
|
46
|
+
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
47
|
+
def default_value(value)
|
48
|
+
# jdbc returns column default strings with actual single quotes around the value.
|
49
|
+
return $1 if value =~ /^'(.*)'$/
|
50
|
+
|
51
|
+
value
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def adapter_name #:nodoc:
|
56
|
+
defined?(::Jdbc::H2) ? 'h2' : 'hsqldb'
|
79
57
|
end
|
80
58
|
|
81
59
|
def modify_types(tp)
|
@@ -84,13 +62,14 @@ module ::JdbcSpec
|
|
84
62
|
tp[:boolean][:limit] = nil
|
85
63
|
# set text and float limits so we don't see odd scales tacked on
|
86
64
|
# in migrations
|
65
|
+
tp[:boolean] = { :name => "tinyint" }
|
87
66
|
tp[:text][:limit] = nil
|
88
|
-
tp[:float][:limit] = 17
|
67
|
+
tp[:float][:limit] = 17 if defined?(::Jdbc::H2)
|
89
68
|
tp[:string][:limit] = 255
|
90
69
|
tp[:datetime] = { :name => "DATETIME" }
|
91
70
|
tp[:timestamp] = { :name => "DATETIME" }
|
92
|
-
tp[:time] = { :name => "
|
93
|
-
tp[:date] = { :name => "
|
71
|
+
tp[:time] = { :name => "TIME" }
|
72
|
+
tp[:date] = { :name => "DATE" }
|
94
73
|
tp
|
95
74
|
end
|
96
75
|
|
@@ -100,9 +79,9 @@ module ::JdbcSpec
|
|
100
79
|
case value
|
101
80
|
when String
|
102
81
|
if respond_to?(:h2_adapter) && value.empty?
|
103
|
-
"
|
82
|
+
"''"
|
104
83
|
elsif column && column.type == :binary
|
105
|
-
"'#{
|
84
|
+
"'#{value.unpack("H*")}'"
|
106
85
|
else
|
107
86
|
"'#{quote_string(value)}'"
|
108
87
|
end
|
@@ -110,6 +89,15 @@ module ::JdbcSpec
|
|
110
89
|
end
|
111
90
|
end
|
112
91
|
|
92
|
+
def quote_column_name(name) #:nodoc:
|
93
|
+
name = name.to_s
|
94
|
+
if name =~ /[-]/
|
95
|
+
%Q{"#{name.upcase}"}
|
96
|
+
else
|
97
|
+
name
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
113
101
|
def quote_string(str)
|
114
102
|
str.gsub(/'/, "''")
|
115
103
|
end
|
@@ -146,6 +134,13 @@ module ::JdbcSpec
|
|
146
134
|
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
|
147
135
|
end
|
148
136
|
|
137
|
+
# Maps logical Rails types to MySQL-specific data types.
|
138
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
139
|
+
return super if defined?(::Jdbc::H2) || type.to_s != 'integer' || limit == nil
|
140
|
+
|
141
|
+
type
|
142
|
+
end
|
143
|
+
|
149
144
|
def rename_table(name, new_name)
|
150
145
|
execute "ALTER TABLE #{name} RENAME TO #{new_name}"
|
151
146
|
end
|
@@ -159,7 +154,7 @@ module ::JdbcSpec
|
|
159
154
|
end
|
160
155
|
|
161
156
|
def last_insert_id(table, sequence_name)
|
162
|
-
Integer(select_value("
|
157
|
+
Integer(select_value("CALL IDENTITY()"))
|
163
158
|
end
|
164
159
|
|
165
160
|
# Override normal #_execute: See Rubyforge #11567
|
@@ -197,4 +192,16 @@ module ::JdbcSpec
|
|
197
192
|
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
198
193
|
end
|
199
194
|
end
|
195
|
+
|
196
|
+
module H2
|
197
|
+
include HSQLDB
|
198
|
+
|
199
|
+
def self.adapter_matcher(name, *)
|
200
|
+
name =~ /\.h2\./i ? self : false
|
201
|
+
end
|
202
|
+
|
203
|
+
def h2_adapter
|
204
|
+
true
|
205
|
+
end
|
206
|
+
end
|
200
207
|
end
|
@@ -40,14 +40,13 @@ module ::JdbcSpec
|
|
40
40
|
@@db_major_version = base.select_one("SELECT dbinfo('version', 'major') version FROM systables WHERE tabid = 1")['version'].to_i
|
41
41
|
end
|
42
42
|
|
43
|
-
def self.
|
44
|
-
|
45
|
-
lambda { |cfg, column| column.extend(::JdbcSpec::Informix::Column) } ]
|
43
|
+
def self.adapter_matcher(name, *)
|
44
|
+
name =~ /informix/i ? self : false
|
46
45
|
end
|
47
46
|
|
48
|
-
def self.
|
47
|
+
def self.column_selector
|
49
48
|
[ /informix/i,
|
50
|
-
lambda { |cfg,
|
49
|
+
lambda { |cfg, column| column.extend(::JdbcSpec::Informix::Column) } ]
|
51
50
|
end
|
52
51
|
|
53
52
|
module Column
|
@@ -1,36 +1,36 @@
|
|
1
1
|
require 'jdbc_adapter/tsql_helper'
|
2
2
|
|
3
|
-
module ::
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
3
|
+
module ::JdbcSpec
|
4
|
+
module MsSQL
|
5
|
+
include TSqlMethods
|
6
|
+
|
7
|
+
def self.extended(mod)
|
8
|
+
unless @lob_callback_added
|
9
|
+
ActiveRecord::Base.class_eval do
|
10
|
+
def after_save_with_mssql_lob
|
11
|
+
self.class.columns.select { |c| c.sql_type =~ /image/i }.each do |c|
|
12
|
+
value = self[c.name]
|
13
|
+
value = value.to_yaml if unserializable_attribute?(c.name, c)
|
14
|
+
next if value.nil? || (value == '')
|
15
|
+
|
16
|
+
connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveRecord::Base.after_save :after_save_with_mssql_lob
|
22
|
+
@lob_callback_added = true
|
16
23
|
end
|
17
24
|
end
|
18
|
-
private :write_lobs
|
19
|
-
end
|
20
|
-
end
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
def self.adapter_matcher(name, *)
|
27
|
+
name =~ /sqlserver|tds/i ? self : false
|
28
|
+
end
|
25
29
|
|
26
30
|
def self.column_selector
|
27
31
|
[/sqlserver|tds/i, lambda {|cfg,col| col.extend(::JdbcSpec::MsSQL::Column)}]
|
28
32
|
end
|
29
33
|
|
30
|
-
def self.adapter_selector
|
31
|
-
[/sqlserver|tds/i, lambda {|cfg,adapt| adapt.extend(::JdbcSpec::MsSQL)}]
|
32
|
-
end
|
33
|
-
|
34
34
|
module Column
|
35
35
|
attr_accessor :identity, :is_special
|
36
36
|
|
@@ -154,11 +154,13 @@ module JdbcSpec
|
|
154
154
|
end
|
155
155
|
|
156
156
|
def drop_database(name)
|
157
|
+
execute "USE master"
|
157
158
|
execute "DROP DATABASE #{name}"
|
158
159
|
end
|
159
160
|
|
160
161
|
def create_database(name)
|
161
162
|
execute "CREATE DATABASE #{name}"
|
163
|
+
execute "USE #{name}"
|
162
164
|
end
|
163
165
|
|
164
166
|
def rename_table(name, new_name)
|