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.
@@ -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
- require 'active_record/connection_adapters/jdbc_adapter'
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
- return value.to_s
88
- end
130
+ return value.to_s if column && column.type == :primary_key
131
+
89
132
  case value
90
- when String
91
- if column && column.type == :binary
92
- "CAST(x'#{quote_string(value).unpack("C*").collect {|v| v.to_s(16)}.join}' AS BLOB)"
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
@@ -0,0 +1,9 @@
1
+ require 'models/entry'
2
+ require 'db/h2'
3
+ require 'simple'
4
+ require 'test/unit'
5
+ require 'db/logger'
6
+
7
+ class H2SimpleTest < Test::Unit::TestCase
8
+ include SimpleTestMethods
9
+ end
@@ -1,8 +1,8 @@
1
+ require 'models/auto_id'
1
2
  require 'models/entry'
2
3
  require 'db/hsqldb'
3
4
  require 'simple'
4
5
  require 'test/unit'
5
- require 'db/logger'
6
6
 
7
7
  class HsqldbSimpleTest < Test::Unit::TestCase
8
8
  include SimpleTestMethods
@@ -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)}