saturnflyer-activerecord-jdbc-adapter 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. data/.gitignore +16 -0
  2. data/History.txt +225 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.txt +161 -0
  5. data/Rakefile +28 -0
  6. data/VERSION +1 -0
  7. data/activerecord-jdbc-adapter.gemspec +277 -0
  8. data/adapters/derby/LICENSE.txt +21 -0
  9. data/adapters/derby/README.txt +5 -0
  10. data/adapters/derby/Rakefile +31 -0
  11. data/adapters/derby/lib/active_record/connection_adapters/jdbcderby_adapter.rb +30 -0
  12. data/adapters/h2/History.txt +0 -0
  13. data/adapters/h2/LICENSE.txt +21 -0
  14. data/adapters/h2/README.txt +5 -0
  15. data/adapters/h2/Rakefile +31 -0
  16. data/adapters/h2/lib/active_record/connection_adapters/jdbch2_adapter.rb +30 -0
  17. data/adapters/hsqldb/History.txt +0 -0
  18. data/adapters/hsqldb/LICENSE.txt +21 -0
  19. data/adapters/hsqldb/README.txt +5 -0
  20. data/adapters/hsqldb/Rakefile +31 -0
  21. data/adapters/hsqldb/lib/active_record/connection_adapters/jdbchsqldb_adapter.rb +30 -0
  22. data/adapters/mysql/History.txt +0 -0
  23. data/adapters/mysql/LICENSE.txt +21 -0
  24. data/adapters/mysql/README.txt +5 -0
  25. data/adapters/mysql/Rakefile +31 -0
  26. data/adapters/mysql/lib/active_record/connection_adapters/jdbcmysql_adapter.rb +30 -0
  27. data/adapters/postgresql/History.txt +0 -0
  28. data/adapters/postgresql/LICENSE.txt +21 -0
  29. data/adapters/postgresql/README.txt +5 -0
  30. data/adapters/postgresql/Rakefile +31 -0
  31. data/adapters/postgresql/lib/active_record/connection_adapters/jdbcpostgresql_adapter.rb +30 -0
  32. data/adapters/sqlite3/LICENSE.txt +21 -0
  33. data/adapters/sqlite3/README.txt +5 -0
  34. data/adapters/sqlite3/Rakefile +31 -0
  35. data/adapters/sqlite3/lib/active_record/connection_adapters/jdbcsqlite3_adapter.rb +30 -0
  36. data/bench/bench_attributes.rb +13 -0
  37. data/bench/bench_attributes_new.rb +14 -0
  38. data/bench/bench_create.rb +12 -0
  39. data/bench/bench_find_all.rb +12 -0
  40. data/bench/bench_find_all_mt.rb +25 -0
  41. data/bench/bench_model.rb +85 -0
  42. data/bench/bench_new.rb +12 -0
  43. data/bench/bench_new_valid.rb +12 -0
  44. data/bench/bench_valid.rb +13 -0
  45. data/drivers/derby/LICENSE.txt +1 -0
  46. data/drivers/derby/README.txt +6 -0
  47. data/drivers/derby/Rakefile +26 -0
  48. data/drivers/derby/lib/derby-10.5.3.0.jar +0 -0
  49. data/drivers/derby/lib/jdbc/derby.rb +11 -0
  50. data/drivers/h2/History.txt +0 -0
  51. data/drivers/h2/LICENSE.txt +2 -0
  52. data/drivers/h2/README.txt +6 -0
  53. data/drivers/h2/Rakefile +26 -0
  54. data/drivers/h2/lib/h2-1.1.107.jar +0 -0
  55. data/drivers/h2/lib/jdbc/h2.rb +10 -0
  56. data/drivers/hsqldb/History.txt +0 -0
  57. data/drivers/hsqldb/LICENSE.txt +2 -0
  58. data/drivers/hsqldb/README.txt +6 -0
  59. data/drivers/hsqldb/Rakefile +26 -0
  60. data/drivers/hsqldb/lib/hsqldb-1.8.0.7.jar +0 -0
  61. data/drivers/hsqldb/lib/jdbc/hsqldb.rb +10 -0
  62. data/drivers/mysql/History.txt +0 -0
  63. data/drivers/mysql/LICENSE.txt +1 -0
  64. data/drivers/mysql/README.txt +6 -0
  65. data/drivers/mysql/Rakefile +26 -0
  66. data/drivers/mysql/lib/jdbc/mysql.rb +10 -0
  67. data/drivers/mysql/lib/mysql-connector-java-5.0.4-bin.jar +0 -0
  68. data/drivers/postgres/History.txt +7 -0
  69. data/drivers/postgres/LICENSE.txt +12 -0
  70. data/drivers/postgres/README.txt +5 -0
  71. data/drivers/postgres/Rakefile +27 -0
  72. data/drivers/postgres/lib/jdbc/postgres.rb +25 -0
  73. data/drivers/postgres/lib/postgresql-8.3-604.jdbc3.jar +0 -0
  74. data/drivers/postgres/lib/postgresql-8.3-604.jdbc4.jar +0 -0
  75. data/drivers/sqlite3/LICENSE.txt +13 -0
  76. data/drivers/sqlite3/README.txt +6 -0
  77. data/drivers/sqlite3/Rakefile +26 -0
  78. data/drivers/sqlite3/lib/jdbc/sqlite3.rb +10 -0
  79. data/drivers/sqlite3/lib/sqlitejdbc-3.6.3.054.jar +0 -0
  80. data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
  81. data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
  82. data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
  83. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
  84. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  85. data/lib/active_record/connection_adapters/jdbc_adapter.rb +637 -0
  86. data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +14 -0
  87. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  88. data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
  89. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  90. data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
  91. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
  92. data/lib/jdbc_adapter.rb +27 -0
  93. data/lib/jdbc_adapter/jdbc.rake +104 -0
  94. data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
  95. data/lib/jdbc_adapter/jdbc_db2.rb +191 -0
  96. data/lib/jdbc_adapter/jdbc_derby.rb +421 -0
  97. data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
  98. data/lib/jdbc_adapter/jdbc_hsqldb.rb +210 -0
  99. data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
  100. data/lib/jdbc_adapter/jdbc_mimer.rb +141 -0
  101. data/lib/jdbc_adapter/jdbc_mssql.rb +333 -0
  102. data/lib/jdbc_adapter/jdbc_mysql.rb +233 -0
  103. data/lib/jdbc_adapter/jdbc_oracle.rb +374 -0
  104. data/lib/jdbc_adapter/jdbc_postgre.rb +483 -0
  105. data/lib/jdbc_adapter/jdbc_sqlite3.rb +360 -0
  106. data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
  107. data/lib/jdbc_adapter/missing_functionality_helper.rb +85 -0
  108. data/lib/jdbc_adapter/rake_tasks.rb +10 -0
  109. data/lib/jdbc_adapter/tsql_helper.rb +60 -0
  110. data/lib/jdbc_adapter/version.rb +5 -0
  111. data/pom.xml +57 -0
  112. data/rakelib/compile.rake +23 -0
  113. data/rakelib/package.rake +73 -0
  114. data/rakelib/rails.rake +41 -0
  115. data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
  116. data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
  117. data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
  118. data/src/java/jdbc_adapter/JdbcMySQLSpec.java +133 -0
  119. data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
  120. data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
  121. data/src/java/jdbc_adapter/RubyJdbcConnection.java +1163 -0
  122. data/src/java/jdbc_adapter/SQLBlock.java +27 -0
  123. data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
  124. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  125. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  126. data/test/activerecord/jall.sh +7 -0
  127. data/test/activerecord/jtest.sh +3 -0
  128. data/test/cachedb_simple_test.rb +6 -0
  129. data/test/db/cachedb.rb +9 -0
  130. data/test/db/db2.rb +9 -0
  131. data/test/db/derby.rb +14 -0
  132. data/test/db/h2.rb +11 -0
  133. data/test/db/hsqldb.rb +12 -0
  134. data/test/db/informix.rb +11 -0
  135. data/test/db/jdbc.rb +11 -0
  136. data/test/db/jndi_config.rb +30 -0
  137. data/test/db/logger.rb +3 -0
  138. data/test/db/mssql.rb +9 -0
  139. data/test/db/mysql.rb +10 -0
  140. data/test/db/oracle.rb +34 -0
  141. data/test/db/postgres.rb +9 -0
  142. data/test/db/sqlite3.rb +15 -0
  143. data/test/db2_simple_test.rb +10 -0
  144. data/test/derby_migration_test.rb +21 -0
  145. data/test/derby_multibyte_test.rb +12 -0
  146. data/test/derby_simple_test.rb +12 -0
  147. data/test/generic_jdbc_connection_test.rb +9 -0
  148. data/test/h2_simple_test.rb +6 -0
  149. data/test/has_many_through.rb +79 -0
  150. data/test/hsqldb_simple_test.rb +6 -0
  151. data/test/informix_simple_test.rb +48 -0
  152. data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
  153. data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
  154. data/test/jdbc_common.rb +24 -0
  155. data/test/jndi_callbacks_test.rb +38 -0
  156. data/test/jndi_test.rb +35 -0
  157. data/test/manualTestDatabase.rb +191 -0
  158. data/test/minirunit.rb +109 -0
  159. data/test/minirunit/testConnect.rb +14 -0
  160. data/test/minirunit/testH2.rb +73 -0
  161. data/test/minirunit/testHsqldb.rb +73 -0
  162. data/test/minirunit/testLoadActiveRecord.rb +3 -0
  163. data/test/minirunit/testMysql.rb +83 -0
  164. data/test/minirunit/testRawSelect.rb +24 -0
  165. data/test/models/add_not_null_column_to_table.rb +12 -0
  166. data/test/models/auto_id.rb +18 -0
  167. data/test/models/data_types.rb +28 -0
  168. data/test/models/entry.rb +23 -0
  169. data/test/models/mixed_case.rb +20 -0
  170. data/test/models/reserved_word.rb +18 -0
  171. data/test/mssql_simple_test.rb +6 -0
  172. data/test/mysql_multibyte_test.rb +10 -0
  173. data/test/mysql_nonstandard_primary_key_test.rb +43 -0
  174. data/test/mysql_simple_test.rb +26 -0
  175. data/test/oracle_simple_test.rb +29 -0
  176. data/test/postgres_mixed_case_test.rb +19 -0
  177. data/test/postgres_nonseq_pkey_test.rb +40 -0
  178. data/test/postgres_reserved_test.rb +22 -0
  179. data/test/postgres_simple_test.rb +12 -0
  180. data/test/simple.rb +397 -0
  181. data/test/sqlite3_simple_test.rb +179 -0
  182. data/test/sybase_jtds_simple_test.rb +6 -0
  183. metadata +294 -0
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2007 David Crawshaw <david@zentus.com>
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
@@ -0,0 +1,6 @@
1
+ This is a SQLite JDBC driver gem for JRuby. Use
2
+
3
+ require 'jdbc/sqlite'
4
+
5
+ to make the driver accessible to JDBC and ActiveRecord code running in JRuby.
6
+
@@ -0,0 +1,26 @@
1
+ MANIFEST = FileList["Manifest.txt", "Rakefile", "README.txt", "LICENSE.txt", "lib/**/*"]
2
+
3
+ file "Manifest.txt" => :manifest
4
+ task :manifest do
5
+ File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
6
+ end
7
+ Rake::Task['manifest'].invoke # Always regen manifest, so Hoe has up-to-date list of files
8
+
9
+ $LOAD_PATH << "lib"
10
+ require "jdbc/sqlite3"
11
+ begin
12
+ require 'hoe'
13
+ Hoe.new("jdbc-sqlite3", Jdbc::SQLite3::VERSION) do |p|
14
+ p.rubyforge_name = "jruby-extras"
15
+ p.url = "http://jruby-extras.rubyforge.org/ActiveRecord-JDBC"
16
+ p.author = "Nick Sieger, Ola Bini and JRuby contributors"
17
+ p.email = "nick@nicksieger.com, ola.bini@gmail.com"
18
+ p.summary = "SQLite3 JDBC driver for Java and SQLite3/ActiveRecord-JDBC."
19
+ p.changes = "Updated to SQLite3 version #{Jdbc::SQLite3::VERSION}."
20
+ p.description = "Install this gem and require 'sqlite3' within JRuby to load the driver."
21
+ end.spec.dependencies.delete_if { |dep| dep.name == "hoe" }
22
+ rescue LoadError
23
+ puts "You really need Hoe installed to be able to package this gem"
24
+ rescue => e
25
+ puts "ignoring error while loading hoe: #{e.to_s}"
26
+ end
@@ -0,0 +1,10 @@
1
+ module Jdbc
2
+ module SQLite3
3
+ VERSION = "3.6.3.054" # Based on SQLite 3.6.3
4
+ end
5
+ end
6
+ if RUBY_PLATFORM =~ /java/
7
+ require "sqlitejdbc-#{Jdbc::SQLite3::VERSION}.jar"
8
+ else
9
+ warn "jdbc-SQLite3 is only for use with JRuby"
10
+ end
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/derby"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-derby"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the derby jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/h2"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-h2"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the hsqldb jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,13 @@
1
+ tried_gem = false
2
+ begin
3
+ require "jdbc/hsqldb"
4
+ rescue LoadError
5
+ unless tried_gem
6
+ require 'rubygems'
7
+ gem "jdbc-hsqldb"
8
+ tried_gem = true
9
+ retry
10
+ end
11
+ # trust that the hsqldb jar is already present
12
+ end
13
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1 @@
1
+ require 'active_record/connection_adapters/jdbc_adapter'
@@ -0,0 +1,637 @@
1
+ require 'active_record/connection_adapters/abstract_adapter'
2
+ require 'java'
3
+ require 'active_record/connection_adapters/jdbc_adapter_spec'
4
+ require 'jdbc_adapter/jdbc_adapter_internal'
5
+ require 'bigdecimal'
6
+
7
+ begin
8
+ require 'jdbc_adapter/rake_tasks'
9
+ rescue LoadError
10
+ end if defined?(RAILS_ROOT)
11
+
12
+ # AR's 2.2 version of this method is sufficient, but we need it for
13
+ # older versions
14
+ if ActiveRecord::VERSION::MAJOR <= 2 && ActiveRecord::VERSION::MINOR < 2
15
+ module ActiveRecord
16
+ module ConnectionAdapters # :nodoc:
17
+ module SchemaStatements
18
+ # Convert the speficied column type to a SQL string.
19
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
20
+ if native = native_database_types[type]
21
+ column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
22
+
23
+ if type == :decimal # ignore limit, use precision and scale
24
+ scale ||= native[:scale]
25
+
26
+ if precision ||= native[:precision]
27
+ if scale
28
+ column_type_sql << "(#{precision},#{scale})"
29
+ else
30
+ column_type_sql << "(#{precision})"
31
+ end
32
+ elsif scale
33
+ raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
34
+ end
35
+
36
+ elsif limit ||= native.is_a?(Hash) && native[:limit]
37
+ column_type_sql << "(#{limit})"
38
+ end
39
+
40
+ column_type_sql
41
+ else
42
+ type
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ module JdbcSpec
51
+ module ActiveRecordExtensions
52
+ def jdbc_connection(config)
53
+ ::ActiveRecord::ConnectionAdapters::JdbcAdapter.new(nil, logger, config)
54
+ end
55
+ alias jndi_connection jdbc_connection
56
+
57
+ def embedded_driver(config)
58
+ config[:username] ||= "sa"
59
+ config[:password] ||= ""
60
+ jdbc_connection(config)
61
+ end
62
+ end
63
+ end
64
+
65
+ module ActiveRecord
66
+ class Base
67
+ extend JdbcSpec::ActiveRecordExtensions
68
+
69
+ alias :attributes_with_quotes_pre_oracle :attributes_with_quotes
70
+ def attributes_with_quotes(include_primary_key = true, *args) #:nodoc:
71
+ aq = attributes_with_quotes_pre_oracle(include_primary_key, *args)
72
+ if connection.class == ConnectionAdapters::JdbcAdapter && (connection.is_a?(JdbcSpec::Oracle) || connection.is_a?(JdbcSpec::Mimer))
73
+ aq[self.class.primary_key] = "?" if include_primary_key && aq[self.class.primary_key].nil?
74
+ end
75
+ aq
76
+ end
77
+ end
78
+
79
+ module ConnectionAdapters
80
+ module Java
81
+ Class = java.lang.Class
82
+ URL = java.net.URL
83
+ URLClassLoader = java.net.URLClassLoader
84
+ end
85
+
86
+ module Jdbc
87
+ Mutex = java.lang.Object.new
88
+ DriverManager = java.sql.DriverManager
89
+ Statement = java.sql.Statement
90
+ Types = java.sql.Types
91
+
92
+ # some symbolic constants for the benefit of the JDBC-based
93
+ # JdbcConnection#indexes method
94
+ module IndexMetaData
95
+ INDEX_NAME = 6
96
+ NON_UNIQUE = 4
97
+ TABLE_NAME = 3
98
+ COLUMN_NAME = 9
99
+ end
100
+
101
+ module TableMetaData
102
+ TABLE_CAT = 1
103
+ TABLE_SCHEM = 2
104
+ TABLE_NAME = 3
105
+ TABLE_TYPE = 4
106
+ end
107
+
108
+ module PrimaryKeyMetaData
109
+ COLUMN_NAME = 4
110
+ end
111
+
112
+ end
113
+
114
+ # I want to use JDBC's DatabaseMetaData#getTypeInfo to choose the best native types to
115
+ # use for ActiveRecord's Adapter#native_database_types in a database-independent way,
116
+ # but apparently a database driver can return multiple types for a given
117
+ # java.sql.Types constant. So this type converter uses some heuristics to try to pick
118
+ # the best (most common) type to use. It's not great, it would be better to just
119
+ # delegate to each database's existin AR adapter's native_database_types method, but I
120
+ # wanted to try to do this in a way that didn't pull in all the other adapters as
121
+ # dependencies. Suggestions appreciated.
122
+ class JdbcTypeConverter
123
+ # The basic ActiveRecord types, mapped to an array of procs that are used to #select
124
+ # the best type. The procs are used as selectors in order until there is only one
125
+ # type left. If all the selectors are applied and there is still more than one
126
+ # type, an exception will be raised.
127
+ AR_TO_JDBC_TYPES = {
128
+ :string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type'].to_i},
129
+ lambda {|r| r['type_name'] =~ /^varchar/i},
130
+ lambda {|r| r['type_name'] =~ /^varchar$/i},
131
+ lambda {|r| r['type_name'] =~ /varying/i}],
132
+ :text => [ lambda {|r| [Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB].include?(r['data_type'].to_i)},
133
+ lambda {|r| r['type_name'] =~ /^text$/i}, # For Informix
134
+ lambda {|r| r['type_name'] =~ /^(text|clob)$/i},
135
+ lambda {|r| r['type_name'] =~ /^character large object$/i},
136
+ lambda {|r| r['sql_data_type'] == 2005}],
137
+ :integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type'].to_i},
138
+ lambda {|r| r['type_name'] =~ /^integer$/i},
139
+ lambda {|r| r['type_name'] =~ /^int4$/i},
140
+ lambda {|r| r['type_name'] =~ /^int$/i}],
141
+ :decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type'].to_i},
142
+ lambda {|r| r['type_name'] =~ /^decimal$/i},
143
+ lambda {|r| r['type_name'] =~ /^numeric$/i},
144
+ lambda {|r| r['type_name'] =~ /^number$/i},
145
+ lambda {|r| r['type_name'] =~ /^real$/i},
146
+ lambda {|r| r['precision'] == '38'},
147
+ lambda {|r| r['data_type'] == '2'}],
148
+ :float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE, Jdbc::Types::REAL].include?(r['data_type'].to_i)},
149
+ lambda {|r| r['data_type'].to_i == Jdbc::Types::REAL}, #Prefer REAL to DOUBLE for Postgresql
150
+ lambda {|r| r['type_name'] =~ /^float/i},
151
+ lambda {|r| r['type_name'] =~ /^double$/i},
152
+ lambda {|r| r['type_name'] =~ /^real$/i},
153
+ lambda {|r| r['precision'] == '15'}],
154
+ :datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
155
+ lambda {|r| r['type_name'] =~ /^datetime$/i},
156
+ lambda {|r| r['type_name'] =~ /^timestamp$/i},
157
+ lambda {|r| r['type_name'] =~ /^date/i},
158
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
159
+ :timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
160
+ lambda {|r| r['type_name'] =~ /^timestamp$/i},
161
+ lambda {|r| r['type_name'] =~ /^datetime/i},
162
+ lambda {|r| r['type_name'] =~ /^date/i},
163
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
164
+ :time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
165
+ lambda {|r| r['type_name'] =~ /^time$/i},
166
+ lambda {|r| r['type_name'] =~ /^datetime/i}, # For Informix
167
+ lambda {|r| r['type_name'] =~ /^date/i},
168
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
169
+ :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
170
+ lambda {|r| r['type_name'] =~ /^date$/i},
171
+ lambda {|r| r['type_name'] =~ /^date/i},
172
+ lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver3
173
+ :binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'].to_i)},
174
+ lambda {|r| r['type_name'] =~ /^blob/i},
175
+ lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
176
+ lambda {|r| r['type_name'] =~ /^varbinary$/i}, # We want this sucker for Mimer
177
+ lambda {|r| r['type_name'] =~ /^binary$/i}, ],
178
+ :boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'].to_i)},
179
+ lambda {|r| r['type_name'] =~ /^bool/i},
180
+ lambda {|r| r['data_type'] == '-7'},
181
+ lambda {|r| r['type_name'] =~ /^tinyint$/i},
182
+ lambda {|r| r['type_name'] =~ /^decimal$/i},
183
+ lambda {|r| r['type_name'] =~ /^integer$/i}]
184
+ }
185
+
186
+ def initialize(types)
187
+ @types = types
188
+ @types.each {|t| t['type_name'] ||= t['local_type_name']} # Sybase driver seems to want 'local_type_name'
189
+ end
190
+
191
+ def choose_best_types
192
+ type_map = {}
193
+ @types.each do |row|
194
+ name = row['type_name'].downcase
195
+ k = name.to_sym
196
+ type_map[k] = { :name => name }
197
+ type_map[k][:limit] = row['precision'].to_i if row['precision']
198
+ end
199
+
200
+ AR_TO_JDBC_TYPES.keys.each do |k|
201
+ typerow = choose_type(k)
202
+ type_map[k] = { :name => typerow['type_name'].downcase }
203
+ case k
204
+ when :integer, :string, :decimal
205
+ type_map[k][:limit] = typerow['precision'] && typerow['precision'].to_i
206
+ when :boolean
207
+ type_map[k][:limit] = 1
208
+ end
209
+ end
210
+ type_map
211
+ end
212
+
213
+ def choose_type(ar_type)
214
+ procs = AR_TO_JDBC_TYPES[ar_type]
215
+ types = @types
216
+ procs.each do |p|
217
+ new_types = types.reject {|r| r["data_type"].to_i == Jdbc::Types::OTHER}
218
+ new_types = new_types.select(&p)
219
+ new_types = new_types.inject([]) do |typs,t|
220
+ typs << t unless typs.detect {|el| el['type_name'] == t['type_name']}
221
+ typs
222
+ end
223
+ return new_types.first if new_types.length == 1
224
+ types = new_types if new_types.length > 0
225
+ end
226
+ raise "unable to choose type for #{ar_type} from:\n#{types.collect{|t| t['type_name']}.inspect}"
227
+ end
228
+ end
229
+
230
+ class JdbcDriver
231
+ def initialize(name)
232
+ @name = name
233
+ end
234
+
235
+ def driver_class
236
+ @driver_class ||= begin
237
+ driver_class_const = (@name[0...1].capitalize + @name[1..@name.length]).gsub(/\./, '_')
238
+ Jdbc::Mutex.synchronized do
239
+ unless Jdbc.const_defined?(driver_class_const)
240
+ driver_class_name = @name
241
+ Jdbc.module_eval do
242
+ include_class(driver_class_name) { driver_class_const }
243
+ end
244
+ end
245
+ end
246
+ driver_class = Jdbc.const_get(driver_class_const)
247
+ raise "You specify a driver for your JDBC connection" unless driver_class
248
+ driver_class
249
+ end
250
+ end
251
+
252
+ def load
253
+ Jdbc::DriverManager.registerDriver(create)
254
+ end
255
+
256
+ def connection(url, user, pass)
257
+ Jdbc::DriverManager.getConnection(url, user, pass)
258
+ rescue
259
+ # bypass DriverManager to get around problem with dynamically loaded jdbc drivers
260
+ props = java.util.Properties.new
261
+ props.setProperty("user", user)
262
+ props.setProperty("password", pass)
263
+ create.connect(url, props)
264
+ end
265
+
266
+ def create
267
+ driver_class.new
268
+ end
269
+ end
270
+
271
+ class JdbcColumn < Column
272
+ attr_writer :limit, :precision
273
+
274
+ COLUMN_TYPES = ::JdbcSpec.constants.map{|c|
275
+ ::JdbcSpec.const_get c }.select{ |c|
276
+ c.respond_to? :column_selector }.map{|c|
277
+ c.column_selector }.inject({}) { |h,val|
278
+ h[val[0]] = val[1]; h }
279
+
280
+ def initialize(config, name, default, *args)
281
+ dialect = config[:dialect] || config[:driver]
282
+ for reg, func in COLUMN_TYPES
283
+ if reg === dialect.to_s
284
+ func.call(config,self)
285
+ end
286
+ end
287
+ super(name,default_value(default),*args)
288
+ init_column(name, default, *args)
289
+ end
290
+
291
+ def init_column(*args)
292
+ end
293
+
294
+ def default_value(val)
295
+ val
296
+ end
297
+ end
298
+
299
+ include_class "jdbc_adapter.JdbcConnectionFactory"
300
+
301
+ class JdbcConnection
302
+ attr_reader :adapter, :connection_factory
303
+
304
+ # @native_database_types - setup properly by adapter= versus set_native_database_types.
305
+ # This contains type information for the adapter. Individual adapters can make tweaks
306
+ # by defined modify_types
307
+ #
308
+ # @native_types - This is the default type settings sans any modifications by the
309
+ # individual adapter. My guess is that if we loaded two adapters of different types
310
+ # then this is used as a base to be tweaked by each adapter to create @native_database_types
311
+
312
+ def initialize(config)
313
+ @config = config.symbolize_keys!
314
+ @config[:retry_count] ||= 5
315
+ @config[:connection_alive_sql] ||= "select 1"
316
+ if @config[:jndi]
317
+ begin
318
+ configure_jndi
319
+ rescue => e
320
+ warn "JNDI data source unavailable: #{e.message}; trying straight JDBC"
321
+ configure_jdbc
322
+ end
323
+ else
324
+ configure_jdbc
325
+ end
326
+ connection # force the connection to load
327
+ set_native_database_types
328
+ @stmts = {}
329
+ rescue Exception => e
330
+ raise "The driver encountered an error: #{e}"
331
+ end
332
+
333
+ def adapter=(adapter)
334
+ @adapter = adapter
335
+ @native_database_types = dup_native_types
336
+ @adapter.modify_types(@native_database_types)
337
+ end
338
+
339
+ # Duplicate all native types into new hash structure so it can be modified
340
+ # without destroying original structure.
341
+ def dup_native_types
342
+ types = {}
343
+ @native_types.each_pair do |k, v|
344
+ types[k] = v.inject({}) do |memo, kv|
345
+ memo[kv.first] = begin kv.last.dup rescue kv.last end
346
+ memo
347
+ end
348
+ end
349
+ types
350
+ end
351
+ private :dup_native_types
352
+
353
+ def jndi_connection?
354
+ @jndi_connection
355
+ end
356
+
357
+ private
358
+ def configure_jndi
359
+ jndi = @config[:jndi].to_s
360
+ ctx = javax.naming.InitialContext.new
361
+ ds = ctx.lookup(jndi)
362
+ @connection_factory = JdbcConnectionFactory.impl do
363
+ ds.connection
364
+ end
365
+ unless @config[:driver]
366
+ @config[:driver] = connection.meta_data.connection.java_class.name
367
+ end
368
+ @jndi_connection = true
369
+ end
370
+
371
+ def configure_jdbc
372
+ driver = @config[:driver].to_s
373
+ user = @config[:username].to_s
374
+ pass = @config[:password].to_s
375
+ url = @config[:url].to_s
376
+
377
+ unless driver && url
378
+ raise ::ActiveRecord::ConnectionFailed, "jdbc adapter requires driver class and url"
379
+ end
380
+
381
+ jdbc_driver = JdbcDriver.new(driver)
382
+ jdbc_driver.load
383
+ @connection_factory = JdbcConnectionFactory.impl do
384
+ jdbc_driver.connection(url, user, pass)
385
+ end
386
+ end
387
+ end
388
+
389
+ class JdbcAdapter < AbstractAdapter
390
+ module ShadowCoreMethods
391
+ def alias_chained_method(meth, feature, target)
392
+ if instance_methods.include?("#{meth}_without_#{feature}")
393
+ alias_method "#{meth}_without_#{feature}".to_sym, target
394
+ else
395
+ alias_method meth, target
396
+ end
397
+ end
398
+ end
399
+
400
+ module CompatibilityMethods
401
+ def self.needed?(base)
402
+ !base.instance_methods.include?("quote_table_name")
403
+ end
404
+
405
+ def quote_table_name(name)
406
+ quote_column_name(name)
407
+ end
408
+ end
409
+
410
+ module ConnectionPoolCallbacks
411
+ def self.included(base)
412
+ base.checkin :on_checkin
413
+ base.checkout :on_checkout
414
+ end
415
+
416
+ def self.needed?
417
+ ActiveRecord::Base.respond_to?(:connection_pool)
418
+ end
419
+
420
+ def on_checkin
421
+ # default implementation does nothing
422
+ end
423
+
424
+ def on_checkout
425
+ # default implementation does nothing
426
+ end
427
+ end
428
+
429
+ module JndiConnectionPoolCallbacks
430
+ def self.prepare(adapter, conn)
431
+ if ActiveRecord::Base.respond_to?(:connection_pool) && conn.jndi_connection?
432
+ adapter.extend self
433
+ conn.disconnect! # disconnect initial connection in JdbcConnection#initialize
434
+ end
435
+ end
436
+
437
+ def on_checkin
438
+ disconnect!
439
+ end
440
+
441
+ def on_checkout
442
+ reconnect!
443
+ end
444
+ end
445
+
446
+ extend ShadowCoreMethods
447
+ include CompatibilityMethods if CompatibilityMethods.needed?(self)
448
+ include ConnectionPoolCallbacks if ConnectionPoolCallbacks.needed?
449
+
450
+ attr_reader :config
451
+
452
+ def initialize(connection, logger, config)
453
+ @config = config
454
+ spec = adapter_spec config
455
+ unless connection
456
+ connection_class = jdbc_connection_class spec
457
+ connection = connection_class.new config
458
+ end
459
+ super(connection, logger)
460
+ extend spec if spec
461
+ connection.adapter = self
462
+ JndiConnectionPoolCallbacks.prepare(self, connection)
463
+ end
464
+
465
+ def jdbc_connection_class(spec)
466
+ connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
467
+ connection_class = ::ActiveRecord::ConnectionAdapters::JdbcConnection unless connection_class
468
+ connection_class
469
+ end
470
+
471
+ # Locate specialized adapter specification if one exists based on config data
472
+ def adapter_spec(config)
473
+ dialect = (config[:dialect] || config[:driver]).to_s
474
+ ::JdbcSpec.constants.map { |name| ::JdbcSpec.const_get name }.each do |constant|
475
+ if constant.respond_to? :adapter_matcher
476
+ spec = constant.adapter_matcher(dialect, config)
477
+ return spec if spec
478
+ end
479
+ end
480
+ nil
481
+ end
482
+
483
+ def modify_types(tp)
484
+ tp
485
+ end
486
+
487
+ def adapter_name #:nodoc:
488
+ 'JDBC'
489
+ end
490
+
491
+ def supports_migrations?
492
+ true
493
+ end
494
+
495
+ def native_database_types #:nodoc:
496
+ @connection.native_database_types
497
+ end
498
+
499
+ def database_name #:nodoc:
500
+ @connection.database_name
501
+ end
502
+
503
+ def native_sql_to_type(tp)
504
+ if /^(.*?)\(([0-9]+)\)/ =~ tp
505
+ tname = $1
506
+ limit = $2.to_i
507
+ ntype = native_database_types
508
+ if ntype[:primary_key] == tp
509
+ return :primary_key,nil
510
+ else
511
+ ntype.each do |name,val|
512
+ if name == :primary_key
513
+ next
514
+ end
515
+ if val[:name].downcase == tname.downcase && (val[:limit].nil? || val[:limit].to_i == limit)
516
+ return name,limit
517
+ end
518
+ end
519
+ end
520
+ elsif /^(.*?)/ =~ tp
521
+ tname = $1
522
+ ntype = native_database_types
523
+ if ntype[:primary_key] == tp
524
+ return :primary_key,nil
525
+ else
526
+ ntype.each do |name,val|
527
+ if val[:name].downcase == tname.downcase && val[:limit].nil?
528
+ return name,nil
529
+ end
530
+ end
531
+ end
532
+ else
533
+ return :string,255
534
+ end
535
+ return nil,nil
536
+ end
537
+
538
+ def reconnect!
539
+ @connection.reconnect!
540
+ @connection
541
+ end
542
+
543
+ def disconnect!
544
+ @connection.disconnect!
545
+ end
546
+
547
+ def jdbc_select_all(sql, name = nil)
548
+ select(sql, name)
549
+ end
550
+ alias_chained_method :select_all, :query_cache, :jdbc_select_all
551
+
552
+ def select_rows(sql, name = nil)
553
+ rows = []
554
+ select(sql, name).each {|row| rows << row.values }
555
+ rows
556
+ end
557
+
558
+ def select_one(sql, name = nil)
559
+ select(sql, name).first
560
+ end
561
+
562
+ def execute(sql, name = nil)
563
+ log(sql, name) do
564
+ _execute(sql,name)
565
+ end
566
+ end
567
+
568
+ # we need to do it this way, to allow Rails stupid tests to always work
569
+ # even if we define a new execute method. Instead of mixing in a new
570
+ # execute, an _execute should be mixed in.
571
+ def _execute(sql, name = nil)
572
+ if JdbcConnection::select?(sql)
573
+ @connection.execute_query(sql)
574
+ elsif JdbcConnection::insert?(sql)
575
+ @connection.execute_insert(sql)
576
+ else
577
+ @connection.execute_update(sql)
578
+ end
579
+ end
580
+
581
+ def jdbc_update(sql, name = nil) #:nodoc:
582
+ execute(sql, name)
583
+ end
584
+ alias_chained_method :update, :query_dirty, :jdbc_update
585
+
586
+ def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
587
+ id = execute(sql, name = nil)
588
+ id_value || id
589
+ end
590
+ alias_chained_method :insert, :query_dirty, :jdbc_insert
591
+
592
+ def jdbc_columns(table_name, name = nil)
593
+ @connection.columns(table_name.to_s)
594
+ end
595
+ alias_chained_method :columns, :query_cache, :jdbc_columns
596
+
597
+ def tables
598
+ @connection.tables
599
+ end
600
+
601
+ def indexes(table_name, name = nil, schema_name = nil)
602
+ @connection.indexes(table_name, name, schema_name)
603
+ end
604
+
605
+ def begin_db_transaction
606
+ @connection.begin
607
+ end
608
+
609
+ def commit_db_transaction
610
+ @connection.commit
611
+ end
612
+
613
+ def rollback_db_transaction
614
+ @connection.rollback
615
+ end
616
+
617
+ def write_large_object(*args)
618
+ @connection.write_large_object(*args)
619
+ end
620
+
621
+ def pk_and_sequence_for(table)
622
+ result_set = @connection.connection.get_meta_data.get_primary_keys(nil, nil, table)
623
+ if result_set.next
624
+ keys = [result_set.getString("COLUMN_NAME"), nil]
625
+ end
626
+ keys.blank? ? nil : keys
627
+ ensure
628
+ result_set.close
629
+ end
630
+
631
+ private
632
+ def select(sql, name=nil)
633
+ execute(sql,name)
634
+ end
635
+ end
636
+ end
637
+ end