ActiveRecord-JDBC 0.2.2 → 0.2.3
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 +13 -0
- data/Manifest.txt +41 -0
- data/README.txt +94 -0
- data/Rakefile +55 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +251 -84
- data/lib/active_record/connection_adapters/jndi_adapter.rb +51 -0
- data/lib/jdbc_adapter.rb +9 -1
- data/lib/jdbc_adapter/jdbc_derby.rb +66 -6
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +50 -2
- data/lib/jdbc_adapter/jdbc_mysql.rb +3 -12
- data/test/activerecord/connection_adapters/type_conversion_test.rb +30 -0
- data/test/db/derby.rb +21 -0
- data/test/db/h2.rb +14 -0
- data/test/db/hsqldb.rb +5 -0
- data/test/derby_simple_test.rb +16 -0
- data/test/h2_simple_test.rb +9 -0
- data/test/hsqldb_simple_test.rb +1 -1
- data/test/minirunit/testH2.rb +73 -0
- data/test/models/auto_id.rb +19 -0
- data/test/models/data_types.rb +19 -0
- data/test/models/entry.rb +3 -4
- data/test/mysql_simple_test.rb +1 -0
- data/test/simple.rb +75 -24
- metadata +39 -39
- data/init.rb +0 -8
- data/install.rb +0 -25
- data/test/activerecord/jall.sh +0 -7
- data/test/activerecord/jtest.sh +0 -3
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
2
|
+
|
3
|
+
module ActiveRecord #:nodoc:
|
4
|
+
class Base #:nodoc:
|
5
|
+
def self.jdbc_connection(config)
|
6
|
+
config.symbolize_keys
|
7
|
+
if config[:jndi]
|
8
|
+
connection = ConnectionAdapters::JndiConnection.new(config)
|
9
|
+
else
|
10
|
+
connection = ConnectionAdapters::JdbcConnection.new(config)
|
11
|
+
end
|
12
|
+
ConnectionAdapters::JdbcAdapter.new(connection, logger, config)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ConnectionAdapters #:nodoc:
|
17
|
+
|
18
|
+
# This adapter allows ActiveRecord to use JNDI to retrieve
|
19
|
+
# a JDBC connection from a previously configured DataSource.
|
20
|
+
# The ActiveRecord configuration looks like this:
|
21
|
+
#
|
22
|
+
# ActiveRecord::Base.establish_connection(
|
23
|
+
# :adapter => 'jdbc',
|
24
|
+
# :jndi => 'java:comp/env/jdbc/test',
|
25
|
+
# :driver => 'sqlserver'
|
26
|
+
# )
|
27
|
+
#
|
28
|
+
# Right now, enough driver information needs to be supplied so that AR-JDBC
|
29
|
+
# can genrate the right flavor of SQL. However, it's not necessary to know
|
30
|
+
# exactly which driver is being used, just enough so the right SQL is generated.
|
31
|
+
#
|
32
|
+
class JndiConnection < JdbcConnection
|
33
|
+
|
34
|
+
def initialize(config)
|
35
|
+
@config = config
|
36
|
+
jndi = @config[:jndi].to_s
|
37
|
+
|
38
|
+
ctx = javax.naming.InitialContext.new
|
39
|
+
ds = ctx.lookup(jndi)
|
40
|
+
@connection = ds.connection
|
41
|
+
set_native_database_types
|
42
|
+
|
43
|
+
@stmts = {}
|
44
|
+
rescue Exception => e
|
45
|
+
raise "The driver encountered an error: #{e}"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/lib/jdbc_adapter.rb
CHANGED
@@ -1 +1,9 @@
|
|
1
|
-
|
1
|
+
if RUBY_PLATFORM =~ /java/
|
2
|
+
if defined?(RAILS_CONNECTION_ADAPTERS)
|
3
|
+
RAILS_CONNECTION_ADAPTERS << %q(jdbc)
|
4
|
+
else
|
5
|
+
RAILS_CONNECTION_ADAPTERS = %w(jdbc)
|
6
|
+
end
|
7
|
+
else
|
8
|
+
raise "ActiveRecord-JDBC is for use with JRuby only"
|
9
|
+
end
|
@@ -82,14 +82,69 @@ module JdbcSpec
|
|
82
82
|
execute "RENAME TABLE #{name} TO #{new_name}"
|
83
83
|
end
|
84
84
|
|
85
|
+
# Support for removing columns added via derby bug issue:
|
86
|
+
# https://issues.apache.org/jira/browse/DERBY-1489
|
87
|
+
#
|
88
|
+
# This feature has not made it into a formal release and is not in Java 6. We will
|
89
|
+
# need to conditionally support this somehow (supposed to arrive for 10.3.0.0)
|
90
|
+
#
|
91
|
+
# def remove_column(table_name, column_name)
|
92
|
+
# execute "ALTER TABLE #{table_name} DROP COLUMN #{column_name} RESTRICT"
|
93
|
+
# end
|
94
|
+
|
95
|
+
# Notes about changing in Derby:
|
96
|
+
# http://db.apache.org/derby/docs/10.2/ref/rrefsqlj81859.html#rrefsqlj81859__rrefsqlj37860)
|
97
|
+
# Derby cannot: Change the column type or decrease the precision of an existing type, but
|
98
|
+
# can increase the types precision only if it is a VARCHAR.
|
99
|
+
#
|
100
|
+
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
101
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{type_to_sql(type, options[:limit])}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def change_column_default(table_name, column_name, default) #:nodoc:
|
105
|
+
execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Support for renaming columns:
|
109
|
+
# https://issues.apache.org/jira/browse/DERBY-1490
|
110
|
+
#
|
111
|
+
# This feature is expect to arrive in version 10.3.0.0:
|
112
|
+
# http://wiki.apache.org/db-derby/DerbyTenThreeRelease)
|
113
|
+
#
|
114
|
+
#def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
115
|
+
# execute "ALTER TABLE #{table_name} ALTER RENAME COLUMN #{column_name} TO #{new_column_name}"
|
116
|
+
#end
|
117
|
+
|
118
|
+
def primary_keys(table_name)
|
119
|
+
@connection.primary_keys table_name.to_s.upcase
|
120
|
+
end
|
121
|
+
|
122
|
+
# For migrations, exclude the primary key index as recommended
|
123
|
+
# by the HSQLDB docs. This is not a great test for primary key
|
124
|
+
# index.
|
125
|
+
def indexes(table_name)
|
126
|
+
@connection.indexes(table_name)
|
127
|
+
end
|
128
|
+
|
85
129
|
def quote(value, column = nil) # :nodoc:
|
86
|
-
if column && column.type == :primary_key
|
87
|
-
|
88
|
-
end
|
130
|
+
return value.to_s if column && column.type == :primary_key
|
131
|
+
|
89
132
|
case value
|
90
|
-
when String
|
91
|
-
if column
|
92
|
-
|
133
|
+
when String
|
134
|
+
if column
|
135
|
+
case column.type
|
136
|
+
when :binary
|
137
|
+
"CAST(x'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}' AS BLOB)"
|
138
|
+
when :string
|
139
|
+
"'#{quote_string(value)}'"
|
140
|
+
else
|
141
|
+
vi = value.to_i
|
142
|
+
if vi.to_s == value
|
143
|
+
value
|
144
|
+
else
|
145
|
+
"'#{quote_string(value)}'"
|
146
|
+
end
|
147
|
+
end
|
93
148
|
else
|
94
149
|
vi = value.to_i
|
95
150
|
if vi.to_s == value
|
@@ -101,6 +156,11 @@ module JdbcSpec
|
|
101
156
|
else super
|
102
157
|
end
|
103
158
|
end
|
159
|
+
|
160
|
+
# For DDL it appears you can quote "" column names, but in queries (like insert it errors out?)
|
161
|
+
# def quote_column_name(name) #:nodoc:
|
162
|
+
# %Q{"#{name}"}
|
163
|
+
# end
|
104
164
|
|
105
165
|
def quoted_true
|
106
166
|
'1'
|
@@ -6,7 +6,7 @@ module JdbcSpec
|
|
6
6
|
case type
|
7
7
|
when :string then value
|
8
8
|
when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
9
|
-
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
9
|
+
when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
|
10
10
|
when :float then value.to_f
|
11
11
|
when :datetime then cast_to_date_or_time(value)
|
12
12
|
when :timestamp then cast_to_time(value)
|
@@ -32,12 +32,36 @@ module JdbcSpec
|
|
32
32
|
(value.hour == 0 and value.min == 0 and value.sec == 0) ?
|
33
33
|
Date.new(value.year, value.month, value.day) : value
|
34
34
|
end
|
35
|
+
|
36
|
+
|
37
|
+
private
|
38
|
+
def simplified_type(field_type)
|
39
|
+
case field_type
|
40
|
+
when /longvarchar/i
|
41
|
+
:text
|
42
|
+
else
|
43
|
+
super(field_type)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Override of ActiveRecord::ConnectionAdapters::Column
|
48
|
+
def extract_limit(sql_type)
|
49
|
+
# HSQLDB appears to return "LONGVARCHAR(0)" for :text columns, which
|
50
|
+
# for AR purposes should be interpreted as "no limit"
|
51
|
+
return nil if sql_type =~ /\(0\)/
|
52
|
+
super
|
53
|
+
end
|
35
54
|
end
|
36
55
|
|
37
56
|
def modify_types(tp)
|
38
57
|
tp[:primary_key] = "INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) PRIMARY KEY"
|
39
58
|
tp[:integer][:limit] = nil
|
40
59
|
tp[:boolean][:limit] = nil
|
60
|
+
# set text and float limits so we don't see odd scales tacked on
|
61
|
+
# in migrations
|
62
|
+
tp[:text][:limit] = nil
|
63
|
+
tp[:float][:limit] = 17
|
64
|
+
tp[:string][:limit] = 255
|
41
65
|
tp[:datetime] = { :name => "DATETIME" }
|
42
66
|
tp[:timestamp] = { :name => "DATETIME" }
|
43
67
|
tp[:time] = { :name => "DATETIME" }
|
@@ -47,7 +71,7 @@ module JdbcSpec
|
|
47
71
|
|
48
72
|
def quote(value, column = nil) # :nodoc:
|
49
73
|
case value
|
50
|
-
when String
|
74
|
+
when String
|
51
75
|
if column && column.type == :binary
|
52
76
|
"'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}'"
|
53
77
|
else
|
@@ -57,6 +81,10 @@ module JdbcSpec
|
|
57
81
|
end
|
58
82
|
end
|
59
83
|
|
84
|
+
def quote_string(str)
|
85
|
+
str.gsub(/'/, "''")
|
86
|
+
end
|
87
|
+
|
60
88
|
def quoted_true
|
61
89
|
'1'
|
62
90
|
end
|
@@ -100,5 +128,25 @@ module JdbcSpec
|
|
100
128
|
sql.replace "select limit #{offset} 0 #{bef}"
|
101
129
|
end
|
102
130
|
end
|
131
|
+
|
132
|
+
# override to filter out system tables that otherwise end
|
133
|
+
# up in db/schema.rb during migrations. JdbcConnection#tables
|
134
|
+
# now takes an optional block filter so we can screen out
|
135
|
+
# rows corresponding to system tables. HSQLDB names its
|
136
|
+
# system tables SYSTEM.*, but H2 seems to name them without
|
137
|
+
# any kind of convention
|
138
|
+
def tables
|
139
|
+
@connection.tables do |result_row|
|
140
|
+
result_row.get_string(ActiveRecord::ConnectionAdapters::Jdbc::TableMetaData::TABLE_TYPE) !~ /^SYSTEM TABLE$/i
|
141
|
+
end
|
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
|
+
|
103
151
|
end
|
104
152
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract/schema_definitions'
|
2
|
+
|
1
3
|
module JdbcSpec
|
2
4
|
module MySQL
|
3
5
|
def modify_types(tp)
|
@@ -73,18 +75,7 @@ module JdbcSpec
|
|
73
75
|
end
|
74
76
|
|
75
77
|
def indexes(table_name, name = nil)#:nodoc:
|
76
|
-
indexes
|
77
|
-
current_index = nil
|
78
|
-
execute("SHOW KEYS FROM #{table_name}", name).each do |row|
|
79
|
-
if current_index != row[2]
|
80
|
-
next if row[2] == "PRIMARY" # skip the primary key
|
81
|
-
current_index = row[2]
|
82
|
-
indexes << IndexDefinition.new(row[0], row[2], row[1] == "0", [])
|
83
|
-
end
|
84
|
-
|
85
|
-
indexes.last.columns << row[4]
|
86
|
-
end
|
87
|
-
indexes
|
78
|
+
@connection.indexes(table_name)
|
88
79
|
end
|
89
80
|
|
90
81
|
def create_table(name, options = {}) #:nodoc:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'models/data_types'
|
3
|
+
require 'db/derby'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
JInteger = java.lang.Integer
|
7
|
+
|
8
|
+
class TypeConversionTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
DbTypeMigration.up
|
12
|
+
DbType.create(
|
13
|
+
:sample_timestamp => Time.at(1169964202),
|
14
|
+
:sample_decimal => JInteger::MAX_VALUE + 1)
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
DbTypeMigration.down
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_timestamp
|
22
|
+
types = DbType.find(:first)
|
23
|
+
assert_equal 'Sun Jan 28 06:03:22 UTC 2007', types.sample_timestamp.getutc.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_decimal
|
27
|
+
types = DbType.find(:first)
|
28
|
+
assert_equal((JInteger::MAX_VALUE + 1), types.sample_decimal)
|
29
|
+
end
|
30
|
+
end
|
data/test/db/derby.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
config = {
|
4
|
+
:adapter => 'jdbc',
|
5
|
+
:username => 'sa',
|
6
|
+
:password => '',
|
7
|
+
:driver => 'org.apache.derby.jdbc.EmbeddedDriver',
|
8
|
+
:url => 'jdbc:derby:derby-testdb;create=true'
|
9
|
+
}
|
10
|
+
|
11
|
+
ActiveRecord::Base.establish_connection(config)
|
12
|
+
logger = Logger.new 'derby-testdb.log'
|
13
|
+
logger.level = Logger::DEBUG
|
14
|
+
ActiveRecord::Base.logger = logger
|
15
|
+
|
16
|
+
at_exit {
|
17
|
+
# Clean up derby files
|
18
|
+
require 'fileutils'
|
19
|
+
Dir.glob('derby-testdb/**/*') {|f| File.delete(f)}
|
20
|
+
FileUtils.rm_r('derby-testdb')
|
21
|
+
}
|
data/test/db/h2.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
config = {
|
2
|
+
:adapter => 'jdbc',
|
3
|
+
:username => 'sa',
|
4
|
+
:password => '',
|
5
|
+
:driver => 'org.h2.Driver',
|
6
|
+
:url => 'jdbc:h2:test.db'
|
7
|
+
}
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection(config)
|
10
|
+
|
11
|
+
at_exit {
|
12
|
+
# Clean up hsqldb when done
|
13
|
+
Dir['test.db*'].each {|f| File.delete(f)}
|
14
|
+
}
|
data/test/db/hsqldb.rb
CHANGED
@@ -4,11 +4,16 @@ config = {
|
|
4
4
|
:password => '',
|
5
5
|
:driver => 'org.hsqldb.jdbcDriver',
|
6
6
|
:url => 'jdbc:hsqldb:test.db'
|
7
|
+
#:url => 'jdbc:hsqldb:mem:test'
|
7
8
|
}
|
8
9
|
|
9
10
|
ActiveRecord::Base.establish_connection(config)
|
11
|
+
logger = Logger.new 'hsqldb-testdb.log'
|
12
|
+
logger.level = Logger::DEBUG
|
13
|
+
ActiveRecord::Base.logger = logger
|
10
14
|
|
11
15
|
at_exit {
|
12
16
|
# Clean up hsqldb when done
|
13
17
|
Dir['test.db*'].each {|f| File.delete(f)}
|
18
|
+
File.delete('hsqldb-testdb.log')
|
14
19
|
}
|
@@ -0,0 +1,16 @@
|
|
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
|
+
|
8
|
+
require 'models/auto_id'
|
9
|
+
require 'models/entry'
|
10
|
+
require 'db/derby'
|
11
|
+
require 'simple'
|
12
|
+
require 'test/unit'
|
13
|
+
|
14
|
+
class DerbySimpleTest < Test::Unit::TestCase
|
15
|
+
include SimpleTestMethods
|
16
|
+
end
|
data/test/hsqldb_simple_test.rb
CHANGED
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
require 'minirunit'
|
3
|
+
|
4
|
+
config = {
|
5
|
+
:adapter => 'jdbc',
|
6
|
+
:username => 'sa',
|
7
|
+
:password => '',
|
8
|
+
:driver => 'org.h2.Driver',
|
9
|
+
:url => 'jdbc:h2:test.db'
|
10
|
+
}
|
11
|
+
RAILS_CONNECTION_ADAPTERS = ['abstract', 'jdbc']
|
12
|
+
|
13
|
+
require 'active_record'
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection(config)
|
16
|
+
require 'logger'
|
17
|
+
ActiveRecord::Base.logger = Logger.new($stdout)
|
18
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
19
|
+
|
20
|
+
class CreateEntries < ActiveRecord::Migration
|
21
|
+
def self.up
|
22
|
+
create_table "entries", :force => true do |t|
|
23
|
+
t.column :title, :string, :limit => 100
|
24
|
+
t.column :updated_on, :datetime
|
25
|
+
t.column :content, :text
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.down
|
30
|
+
drop_table "entries"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
CreateEntries.up
|
35
|
+
|
36
|
+
test_ok ActiveRecord::Base.connection.tables.include?('entries')
|
37
|
+
|
38
|
+
class Entry < ActiveRecord::Base
|
39
|
+
end
|
40
|
+
|
41
|
+
Entry.delete_all
|
42
|
+
|
43
|
+
test_equal 0, Entry.count
|
44
|
+
|
45
|
+
TITLE = "First post!"
|
46
|
+
CONTENT = "Hello from JRuby on Rails!"
|
47
|
+
NEW_TITLE = "First post updated title"
|
48
|
+
|
49
|
+
post = Entry.new
|
50
|
+
post.title = TITLE
|
51
|
+
post.content = CONTENT
|
52
|
+
post.save
|
53
|
+
|
54
|
+
test_equal 1, Entry.count
|
55
|
+
|
56
|
+
post = Entry.find(:first)
|
57
|
+
test_equal TITLE, post.title
|
58
|
+
test_equal CONTENT, post.content
|
59
|
+
|
60
|
+
post.title = NEW_TITLE
|
61
|
+
post.save
|
62
|
+
|
63
|
+
post = Entry.find(:first)
|
64
|
+
test_equal NEW_TITLE, post.title
|
65
|
+
|
66
|
+
post.destroy
|
67
|
+
|
68
|
+
test_equal 0, Entry.count
|
69
|
+
|
70
|
+
CreateEntries.down
|
71
|
+
|
72
|
+
# Clean up hsqldb when done
|
73
|
+
Dir['test.db*'].each {|f| File.delete(f)}
|