tgbyte-activerecord-jdbc-adapter 1.2.2.2

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.
Files changed (218) hide show
  1. data/.gitignore +22 -0
  2. data/.travis.yml +8 -0
  3. data/Gemfile +14 -0
  4. data/Gemfile.lock +40 -0
  5. data/History.txt +488 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.rdoc +199 -0
  8. data/Rakefile +60 -0
  9. data/activerecord-jdbc-adapter.gemspec +23 -0
  10. data/bench/bench_attributes.rb +13 -0
  11. data/bench/bench_attributes_new.rb +14 -0
  12. data/bench/bench_create.rb +12 -0
  13. data/bench/bench_find_all.rb +12 -0
  14. data/bench/bench_find_all_mt.rb +25 -0
  15. data/bench/bench_model.rb +85 -0
  16. data/bench/bench_new.rb +12 -0
  17. data/bench/bench_new_valid.rb +12 -0
  18. data/bench/bench_valid.rb +13 -0
  19. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  31. data/lib/activerecord-jdbc-adapter.rb +8 -0
  32. data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
  33. data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
  34. data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
  35. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +15 -0
  36. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
  37. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +46 -0
  38. data/lib/arel/visitors/compat.rb +13 -0
  39. data/lib/arel/visitors/db2.rb +17 -0
  40. data/lib/arel/visitors/derby.rb +32 -0
  41. data/lib/arel/visitors/firebird.rb +24 -0
  42. data/lib/arel/visitors/hsqldb.rb +26 -0
  43. data/lib/arel/visitors/sql_server.rb +46 -0
  44. data/lib/arjdbc.rb +24 -0
  45. data/lib/arjdbc/db2.rb +2 -0
  46. data/lib/arjdbc/db2/adapter.rb +510 -0
  47. data/lib/arjdbc/derby.rb +7 -0
  48. data/lib/arjdbc/derby/adapter.rb +358 -0
  49. data/lib/arjdbc/derby/connection_methods.rb +19 -0
  50. data/lib/arjdbc/discover.rb +92 -0
  51. data/lib/arjdbc/firebird.rb +2 -0
  52. data/lib/arjdbc/firebird/adapter.rb +136 -0
  53. data/lib/arjdbc/h2.rb +4 -0
  54. data/lib/arjdbc/h2/adapter.rb +54 -0
  55. data/lib/arjdbc/h2/connection_methods.rb +13 -0
  56. data/lib/arjdbc/hsqldb.rb +4 -0
  57. data/lib/arjdbc/hsqldb/adapter.rb +184 -0
  58. data/lib/arjdbc/hsqldb/connection_methods.rb +15 -0
  59. data/lib/arjdbc/informix.rb +3 -0
  60. data/lib/arjdbc/informix/adapter.rb +138 -0
  61. data/lib/arjdbc/informix/connection_methods.rb +11 -0
  62. data/lib/arjdbc/jdbc.rb +2 -0
  63. data/lib/arjdbc/jdbc/adapter.rb +356 -0
  64. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  65. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  66. data/lib/arjdbc/jdbc/callbacks.rb +44 -0
  67. data/lib/arjdbc/jdbc/column.rb +47 -0
  68. data/lib/arjdbc/jdbc/compatibility.rb +51 -0
  69. data/lib/arjdbc/jdbc/connection.rb +134 -0
  70. data/lib/arjdbc/jdbc/connection_methods.rb +16 -0
  71. data/lib/arjdbc/jdbc/core_ext.rb +24 -0
  72. data/lib/arjdbc/jdbc/discover.rb +18 -0
  73. data/lib/arjdbc/jdbc/driver.rb +35 -0
  74. data/lib/arjdbc/jdbc/extension.rb +47 -0
  75. data/lib/arjdbc/jdbc/java.rb +14 -0
  76. data/lib/arjdbc/jdbc/jdbc.rake +131 -0
  77. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +88 -0
  78. data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
  79. data/lib/arjdbc/jdbc/railtie.rb +9 -0
  80. data/lib/arjdbc/jdbc/rake_tasks.rb +10 -0
  81. data/lib/arjdbc/jdbc/require_driver.rb +16 -0
  82. data/lib/arjdbc/jdbc/type_converter.rb +126 -0
  83. data/lib/arjdbc/mimer.rb +2 -0
  84. data/lib/arjdbc/mimer/adapter.rb +142 -0
  85. data/lib/arjdbc/mssql.rb +4 -0
  86. data/lib/arjdbc/mssql/adapter.rb +477 -0
  87. data/lib/arjdbc/mssql/connection_methods.rb +31 -0
  88. data/lib/arjdbc/mssql/limit_helpers.rb +101 -0
  89. data/lib/arjdbc/mssql/lock_helpers.rb +72 -0
  90. data/lib/arjdbc/mssql/tsql_helper.rb +61 -0
  91. data/lib/arjdbc/mysql.rb +4 -0
  92. data/lib/arjdbc/mysql/adapter.rb +505 -0
  93. data/lib/arjdbc/mysql/connection_methods.rb +28 -0
  94. data/lib/arjdbc/oracle.rb +3 -0
  95. data/lib/arjdbc/oracle/adapter.rb +428 -0
  96. data/lib/arjdbc/oracle/connection_methods.rb +12 -0
  97. data/lib/arjdbc/postgresql.rb +4 -0
  98. data/lib/arjdbc/postgresql/adapter.rb +825 -0
  99. data/lib/arjdbc/postgresql/connection_methods.rb +23 -0
  100. data/lib/arjdbc/sqlite3.rb +4 -0
  101. data/lib/arjdbc/sqlite3/adapter.rb +389 -0
  102. data/lib/arjdbc/sqlite3/connection_methods.rb +35 -0
  103. data/lib/arjdbc/sybase.rb +2 -0
  104. data/lib/arjdbc/sybase/adapter.rb +46 -0
  105. data/lib/arjdbc/version.rb +8 -0
  106. data/lib/generators/jdbc/USAGE +10 -0
  107. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  108. data/lib/jdbc_adapter.rb +2 -0
  109. data/lib/jdbc_adapter/rake_tasks.rb +3 -0
  110. data/lib/jdbc_adapter/version.rb +3 -0
  111. data/lib/pg.rb +26 -0
  112. data/pom.xml +57 -0
  113. data/rails_generators/jdbc_generator.rb +15 -0
  114. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  115. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  116. data/rakelib/bundler_ext.rb +11 -0
  117. data/rakelib/compile.rake +23 -0
  118. data/rakelib/db.rake +39 -0
  119. data/rakelib/rails.rake +41 -0
  120. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +62 -0
  121. data/src/java/arjdbc/derby/DerbyModule.java +324 -0
  122. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +70 -0
  123. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
  124. data/src/java/arjdbc/jdbc/AdapterJavaService.java +68 -0
  125. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +36 -0
  126. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1326 -0
  127. data/src/java/arjdbc/jdbc/SQLBlock.java +48 -0
  128. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +127 -0
  129. data/src/java/arjdbc/mysql/MySQLModule.java +134 -0
  130. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +161 -0
  131. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
  132. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +82 -0
  133. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +126 -0
  134. data/test/abstract_db_create.rb +135 -0
  135. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  136. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  137. data/test/activerecord/jall.sh +7 -0
  138. data/test/activerecord/jtest.sh +3 -0
  139. data/test/db/db2.rb +11 -0
  140. data/test/db/derby.rb +12 -0
  141. data/test/db/h2.rb +11 -0
  142. data/test/db/hsqldb.rb +13 -0
  143. data/test/db/informix.rb +11 -0
  144. data/test/db/jdbc.rb +12 -0
  145. data/test/db/jndi_config.rb +40 -0
  146. data/test/db/logger.rb +3 -0
  147. data/test/db/mssql.rb +9 -0
  148. data/test/db/mysql.rb +10 -0
  149. data/test/db/oracle.rb +34 -0
  150. data/test/db/postgres.rb +9 -0
  151. data/test/db/sqlite3.rb +11 -0
  152. data/test/db2_reset_column_information_test.rb +8 -0
  153. data/test/db2_simple_test.rb +66 -0
  154. data/test/derby_migration_test.rb +68 -0
  155. data/test/derby_multibyte_test.rb +12 -0
  156. data/test/derby_reset_column_information_test.rb +8 -0
  157. data/test/derby_row_locking_test.rb +9 -0
  158. data/test/derby_simple_test.rb +139 -0
  159. data/test/generic_jdbc_connection_test.rb +29 -0
  160. data/test/h2_change_column_test.rb +68 -0
  161. data/test/h2_simple_test.rb +41 -0
  162. data/test/has_many_through.rb +79 -0
  163. data/test/helper.rb +87 -0
  164. data/test/hsqldb_simple_test.rb +6 -0
  165. data/test/informix_simple_test.rb +48 -0
  166. data/test/jdbc_common.rb +28 -0
  167. data/test/jndi_callbacks_test.rb +36 -0
  168. data/test/jndi_test.rb +25 -0
  169. data/test/manualTestDatabase.rb +191 -0
  170. data/test/models/add_not_null_column_to_table.rb +9 -0
  171. data/test/models/auto_id.rb +15 -0
  172. data/test/models/data_types.rb +30 -0
  173. data/test/models/entry.rb +40 -0
  174. data/test/models/mixed_case.rb +22 -0
  175. data/test/models/reserved_word.rb +15 -0
  176. data/test/models/string_id.rb +17 -0
  177. data/test/models/thing.rb +16 -0
  178. data/test/models/validates_uniqueness_of_string.rb +19 -0
  179. data/test/mssql_db_create_test.rb +26 -0
  180. data/test/mssql_identity_insert_test.rb +19 -0
  181. data/test/mssql_ignore_system_views_test.rb +27 -0
  182. data/test/mssql_legacy_types_test.rb +58 -0
  183. data/test/mssql_limit_offset_test.rb +136 -0
  184. data/test/mssql_multibyte_test.rb +18 -0
  185. data/test/mssql_null_test.rb +14 -0
  186. data/test/mssql_reset_column_information_test.rb +8 -0
  187. data/test/mssql_row_locking_sql_test.rb +159 -0
  188. data/test/mssql_row_locking_test.rb +9 -0
  189. data/test/mssql_simple_test.rb +55 -0
  190. data/test/mysql_db_create_test.rb +27 -0
  191. data/test/mysql_index_length_test.rb +58 -0
  192. data/test/mysql_info_test.rb +123 -0
  193. data/test/mysql_multibyte_test.rb +10 -0
  194. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  195. data/test/mysql_reset_column_information_test.rb +8 -0
  196. data/test/mysql_simple_test.rb +125 -0
  197. data/test/oracle_reset_column_information_test.rb +8 -0
  198. data/test/oracle_simple_test.rb +18 -0
  199. data/test/oracle_specific_test.rb +83 -0
  200. data/test/postgres_db_create_test.rb +32 -0
  201. data/test/postgres_drop_db_test.rb +16 -0
  202. data/test/postgres_information_schema_leak_test.rb +29 -0
  203. data/test/postgres_mixed_case_test.rb +29 -0
  204. data/test/postgres_native_type_mapping_test.rb +89 -0
  205. data/test/postgres_nonseq_pkey_test.rb +38 -0
  206. data/test/postgres_reserved_test.rb +22 -0
  207. data/test/postgres_reset_column_information_test.rb +8 -0
  208. data/test/postgres_schema_search_path_test.rb +48 -0
  209. data/test/postgres_simple_test.rb +167 -0
  210. data/test/postgres_table_alias_length_test.rb +15 -0
  211. data/test/postgres_type_conversion_test.rb +34 -0
  212. data/test/row_locking.rb +90 -0
  213. data/test/simple.rb +717 -0
  214. data/test/sqlite3_reset_column_information_test.rb +8 -0
  215. data/test/sqlite3_simple_test.rb +316 -0
  216. data/test/sybase_jtds_simple_test.rb +28 -0
  217. data/test/sybase_reset_column_information_test.rb +8 -0
  218. metadata +275 -0
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/bench_model'
2
+
3
+ puts "Widget.new"
4
+ Benchmark.bm do |make|
5
+ TIMES.times do
6
+ make.report do
7
+ 100_000.times do
8
+ Widget.new
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/bench_model'
2
+
3
+ puts "Widget.new.valid?"
4
+ Benchmark.bm do |make|
5
+ TIMES.times do
6
+ make.report do
7
+ 100_000.times do
8
+ Widget.new.valid?
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/bench_model'
2
+
3
+ puts "Widget.new.valid?"
4
+ Benchmark.bm do |make|
5
+ TIMES.times do
6
+ make.report do
7
+ widget = Widget.new
8
+ 100_000.times do
9
+ widget.valid?
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1 @@
1
+ require 'arjdbc/derby'
@@ -0,0 +1 @@
1
+ require 'arjdbc/h2'
@@ -0,0 +1 @@
1
+ require 'arjdbc/hsqldb'
@@ -0,0 +1 @@
1
+ require 'arjdbc/informix'
@@ -0,0 +1 @@
1
+ require 'arjdbc/jdbc'
@@ -0,0 +1 @@
1
+ require 'arjdbc/jdbc'
@@ -0,0 +1 @@
1
+ require 'arjdbc/mssql'
@@ -0,0 +1 @@
1
+ require 'arjdbc/mysql'
@@ -0,0 +1 @@
1
+ require 'arjdbc/mysql'
@@ -0,0 +1 @@
1
+ require 'arjdbc/oracle'
@@ -0,0 +1 @@
1
+ require 'arjdbc/postgresql'
@@ -0,0 +1 @@
1
+ require 'arjdbc/sqlite3'
@@ -0,0 +1,8 @@
1
+ require 'arjdbc'
2
+ if defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
3
+ begin
4
+ require 'arjdbc/jdbc/railtie'
5
+ rescue LoadError
6
+ # Assume we don't have railties in this version of AR
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'arel/engines/sql/compilers/ibm_db_compiler'
2
+
3
+ module Arel
4
+ module SqlCompiler
5
+ class DB2Compiler < IBM_DBCompiler
6
+ end
7
+ end
8
+ end
9
+
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class DerbyCompiler < GenericCompiler
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class H2Compiler < GenericCompiler
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class HsqldbCompiler < GenericCompiler
4
+ def select_sql
5
+ # HSQLDB needs to add LIMIT in right after SELECT
6
+ query = super
7
+ offset = relation.skipped
8
+ limit = relation.taken
9
+ @engine.connection.add_limit_offset!(query, :limit => limit,
10
+ :offset => offset) if offset || limit
11
+ query
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class JDBCCompiler < GenericCompiler
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,46 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class MsSQLCompiler < GenericCompiler
4
+ def select_sql
5
+ projections = @relation.projections
6
+ offset = relation.skipped
7
+ limit = relation.taken
8
+ if Count === projections.first && projections.size == 1 &&
9
+ (relation.taken.present? || relation.wheres.present?) && relation.joins(self).blank?
10
+ subquery = [
11
+ "SELECT * FROM #{relation.from_clauses}", build_clauses
12
+ ].join ' '
13
+ @engine.connection.add_limit_offset!(subquery, :limit => limit, :offset => offset) if offset || limit
14
+ query = "SELECT COUNT(*) AS count_id FROM (#{subquery}) AS subquery"
15
+ else
16
+ query = [
17
+ "SELECT #{relation.select_clauses.join(', ')}",
18
+ "FROM #{relation.from_clauses}",
19
+ build_clauses
20
+ ].compact.join ' '
21
+ @engine.connection.add_limit_offset!(query, :limit => limit, :offset => offset) if offset || limit
22
+ end
23
+ query
24
+ end
25
+
26
+ def build_clauses
27
+ joins = relation.joins(self)
28
+ wheres = relation.where_clauses
29
+ groups = relation.group_clauses
30
+ havings = relation.having_clauses
31
+ orders = relation.order_clauses
32
+
33
+ clauses = [ "",
34
+ joins,
35
+ ("WHERE #{wheres.join(' AND ')}" unless wheres.empty?),
36
+ ("GROUP BY #{groups.join(', ')}" unless groups.empty?),
37
+ ("HAVING #{havings.join(' AND ')}" unless havings.empty?),
38
+ ("ORDER BY #{orders.join(', ')}" unless orders.empty?)
39
+ ].compact.join ' '
40
+
41
+ clauses << " #{locked}" unless locked.blank?
42
+ clauses unless clauses.blank?
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ module Arel
2
+ module Visitors
3
+ module ArJdbcCompat
4
+ def limit_for(limit_or_node)
5
+ limit_or_node.respond_to?(:expr) ? limit_or_node.expr.to_i : limit_or_node
6
+ end
7
+ end
8
+
9
+ class ToSql
10
+ include ArJdbcCompat
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class DB2 < Arel::Visitors::ToSql
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ add_limit_offset([o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
8
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
9
+ ].compact.join(' '), o)
10
+ end
11
+
12
+ def add_limit_offset(sql, o)
13
+ @connection.replace_limit_offset! sql, limit_for(o.limit), o.offset && o.offset.value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class Derby < Arel::Visitors::ToSql
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ [
8
+ o.cores.map { |x| visit(x) }.join,
9
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
10
+ (visit(o.offset) if o.offset),
11
+ (visit(o.limit) if o.limit),
12
+ (visit(o.lock) if o.lock),
13
+ ].compact.join ' '
14
+ end
15
+
16
+ def visit_Arel_Nodes_Limit o
17
+ "FETCH FIRST #{limit_for(o)} ROWS ONLY"
18
+ end
19
+
20
+ def visit_Arel_Nodes_Offset o
21
+ "OFFSET #{visit o.value} ROWS"
22
+ end
23
+
24
+ # This generates SELECT...FOR UPDATE, but it will only work if the
25
+ # current transaction isolation level is set to SERIALIZABLE. Otherwise,
26
+ # locks aren't held for the entire transaction.
27
+ def visit_Arel_Nodes_Lock o
28
+ visit o.expr
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class Firebird < Arel::Visitors::ToSql
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ lim_off = [
8
+ ("FIRST #{visit(o.limit.expr)}" if o.limit),
9
+ ("SKIP #{visit(o.offset.expr)}" if o.offset)
10
+ ].compact.join(' ').strip
11
+
12
+ sql = [
13
+ o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
14
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
15
+ ].compact.join ' '
16
+
17
+ sql.sub!(/\A(\s*SELECT\s)/i, '\&' + lim_off + ' ') unless lim_off.empty?
18
+
19
+ sql
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class HSQLDB < Arel::Visitors::ToSql
6
+ def visit_Arel_Nodes_SelectStatement o
7
+ [
8
+ limit_offset(o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join, o),
9
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
10
+ ].compact.join ' '
11
+ end
12
+
13
+ def limit_offset sql, o
14
+ offset = o.offset || 0
15
+ bef = sql[7..-1]
16
+ if limit = o.limit
17
+ "SELECT LIMIT #{offset} #{limit_for(limit)} #{bef}"
18
+ elsif offset > 0
19
+ "SELECT LIMIT #{offset} 0 #{bef}"
20
+ else
21
+ sql
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ require 'arel/visitors/compat'
2
+
3
+ module Arel
4
+ module Visitors
5
+ class SQLServer < Arel::Visitors::ToSql
6
+ include ArJdbc::MsSQL::LimitHelpers::SqlServerReplaceLimitOffset
7
+ include ArJdbc::MsSQL::LockHelpers::SqlServerAddLock
8
+
9
+ def select_count? o
10
+ sel = o.cores.length == 1 && o.cores.first
11
+ projections = sel && sel.projections.length == 1 && sel.projections
12
+ projections && Arel::Nodes::Count === projections.first
13
+ end
14
+
15
+ # Need to mimic the subquery logic in ARel 1.x for select count with limit
16
+ # See arel/engines/sql/compilers/mssql_compiler.rb for details
17
+ def visit_Arel_Nodes_SelectStatement o
18
+ order = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
19
+ if o.limit
20
+ if select_count?(o)
21
+ subquery = true
22
+ sql = o.cores.map do |x|
23
+ x = x.dup
24
+ x.projections = [Arel::Nodes::SqlLiteral.new("*")]
25
+ visit_Arel_Nodes_SelectCore x
26
+ end.join
27
+ else
28
+ sql = o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join
29
+ end
30
+
31
+ order ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
32
+ replace_limit_offset!(sql, limit_for(o.limit).to_i, o.offset && o.offset.value.to_i, order)
33
+ sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if subquery
34
+ else
35
+ sql = super
36
+ end
37
+ add_lock!(sql, :lock => o.lock && true)
38
+ sql
39
+ end
40
+ end
41
+
42
+ class SQLServer2000 < SQLServer
43
+ include ArJdbc::MsSQL::LimitHelpers::SqlServer2000ReplaceLimitOffset
44
+ end
45
+ end
46
+ end
data/lib/arjdbc.rb ADDED
@@ -0,0 +1,24 @@
1
+ if defined?(JRUBY_VERSION)
2
+ begin
3
+ require 'active_record/version'
4
+ if ActiveRecord::VERSION::MAJOR < 2
5
+ if defined?(RAILS_CONNECTION_ADAPTERS)
6
+ RAILS_CONNECTION_ADAPTERS << %q(jdbc)
7
+ else
8
+ RAILS_CONNECTION_ADAPTERS = %w(jdbc)
9
+ end
10
+ if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
11
+ require 'arjdbc/jdbc'
12
+ end
13
+ else
14
+ require 'active_record'
15
+ require 'arjdbc/jdbc'
16
+ end
17
+ rescue LoadError
18
+ warn "activerecord-jdbc-adapter requires ActiveRecord at runtime"
19
+ end
20
+ else
21
+ warn "activerecord-jdbc-adapter is for use with JRuby only"
22
+ end
23
+
24
+ require 'arjdbc/version'
data/lib/arjdbc/db2.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'arjdbc/jdbc'
2
+ require 'arjdbc/db2/adapter'
@@ -0,0 +1,510 @@
1
+ module ArJdbc
2
+ module DB2
3
+ def self.extended(base)
4
+ if base.zos?
5
+ unless @lob_callback_added
6
+ ActiveRecord::Base.class_eval do
7
+ def after_save_with_db2zos_blob
8
+ lobfields = self.class.columns.select { |c| c.sql_type =~ /blob|clob/i }
9
+ lobfields.each do |c|
10
+ value = self[c.name]
11
+ value = value.to_yaml if unserializable_attribute?(c.name, c)
12
+ next if value.nil?
13
+ connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
14
+ end
15
+ end
16
+ end
17
+
18
+ ActiveRecord::Base.after_save :after_save_with_db2zos_blob
19
+
20
+ @lob_callback_added = true
21
+ end
22
+ end
23
+ end
24
+
25
+ def self.column_selector
26
+ [ /(db2|as400|zos)/i,
27
+ lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
28
+ end
29
+
30
+ def self.jdbc_connection_class
31
+ ::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
32
+ end
33
+
34
+ module Column
35
+ def type_cast(value)
36
+ return nil if value.nil? || value =~ /^\s*null\s*$/i
37
+ case type
38
+ when :string then value
39
+ when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
40
+ when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
41
+ when :float then value.to_f
42
+ when :datetime then ArJdbc::DB2::Column.cast_to_date_or_time(value)
43
+ when :date then ArJdbc::DB2::Column.cast_to_date_or_time(value)
44
+ when :timestamp then ArJdbc::DB2::Column.cast_to_time(value)
45
+ when :time then ArJdbc::DB2::Column.cast_to_time(value)
46
+ # TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ def type_cast_code(var_name)
53
+ case type
54
+ when :datetime then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
55
+ when :date then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
56
+ when :timestamp then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
57
+ when :time then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ def self.cast_to_date_or_time(value)
64
+ return value if value.is_a? Date
65
+ return nil if value.blank?
66
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
67
+ end
68
+
69
+ def self.cast_to_time(value)
70
+ return value if value.is_a? Time
71
+ # AS400 returns a 2 digit year, LUW returns a 4 digit year, so comp = true to help out AS400
72
+ time = DateTime.parse(value).to_time rescue nil
73
+ return nil unless time
74
+ time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
75
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
76
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
77
+ end
78
+
79
+ def self.guess_date_or_time(value)
80
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
81
+ Date.new(value.year, value.month, value.day) : value
82
+ end
83
+
84
+ private
85
+ # <b>DEPRECATED:</b> SMALLINT is now used for boolean field types. Please
86
+ # convert your tables using DECIMAL(5) for boolean values to SMALLINT instead.
87
+ def use_decimal5_for_boolean
88
+ warn "[DEPRECATION] using DECIMAL(5) for boolean is deprecated. Convert your columns to SMALLINT instead."
89
+ :boolean
90
+ end
91
+
92
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
93
+ def simplified_type(field_type)
94
+ case field_type
95
+ # old jdbc_db2.rb used decimal(5,0) as boolean
96
+ when /^smallint/i then :boolean
97
+ when /^decimal\(5\)$/i then use_decimal5_for_boolean
98
+ when /^real/i then :float
99
+ when /^timestamp/i then :datetime
100
+ else
101
+ super
102
+ end
103
+ end
104
+
105
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
106
+ def default_value(value)
107
+ # IBM i (AS400) will return an empty string instead of null for no default
108
+ return nil if value.blank?
109
+
110
+ # string defaults are surrounded by single quotes
111
+ return $1 if value =~ /^'(.*)'$/
112
+
113
+ value
114
+ end
115
+ end
116
+
117
+ def _execute(sql, name = nil)
118
+ if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
119
+ @connection.execute_query(sql)
120
+ elsif ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
121
+ (@connection.execute_insert(sql) or last_insert_id(sql)).to_i
122
+ else
123
+ @connection.execute_update(sql)
124
+ end
125
+ end
126
+
127
+ # holy moly batman! all this to tell AS400 "yes i am sure"
128
+ def execute_and_auto_confirm(sql)
129
+ begin
130
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
131
+ @connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
132
+ rescue Exception => e
133
+ raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
134
+ "Do you have authority to do this?\n\n" + e.to_s
135
+ end
136
+
137
+ r = execute sql
138
+
139
+ begin
140
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
141
+ @connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
142
+ rescue Exception => e
143
+ raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
144
+ "Do you have authority to do this?\n\n" + e.to_s
145
+ end
146
+ r
147
+ end
148
+
149
+ def last_insert_id(sql)
150
+ table_name = sql.split(/\s/)[2]
151
+ result = select(ActiveRecord::Base.send(:sanitize_sql,
152
+ %[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}],
153
+ nil))
154
+ result.last['last_insert_id']
155
+ end
156
+
157
+ def modify_types(tp)
158
+ tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
159
+ tp[:string][:limit] = 255
160
+ tp[:integer][:limit] = nil
161
+ tp[:boolean] = {:name => "smallint"}
162
+ tp
163
+ end
164
+
165
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
166
+ limit = nil if type.to_sym == :integer
167
+ super(type, limit, precision, scale)
168
+ end
169
+
170
+ def adapter_name
171
+ 'DB2'
172
+ end
173
+
174
+ def self.arel2_visitors(config)
175
+ require 'arel/visitors/db2'
176
+ {}.tap {|v| %w(db2 as400).each {|a| v[a] = ::Arel::Visitors::DB2 } }
177
+ end
178
+
179
+ def add_limit_offset!(sql, options)
180
+ replace_limit_offset!(sql, options[:limit], options[:offset])
181
+ end
182
+
183
+
184
+ def create_table(name, options = {}) #:nodoc:
185
+ if zos?
186
+ table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
187
+
188
+ table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(name)) unless options[:id] == false
189
+
190
+ yield table_definition
191
+
192
+ # Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
193
+ # First: Save them for later in Array "clobs"
194
+ clobs =table_definition.columns.select { |x| x.type == "text" }
195
+
196
+ # Second: and delete them from the original Colums-Array
197
+ table_definition.columns.delete_if { |x| x.type=="text" }
198
+
199
+ if options[:force] && table_exists?(name)
200
+ super.drop_table(name, options)
201
+ end
202
+
203
+ create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
204
+ create_sql << "#{quote_table_name(name)} ("
205
+ create_sql << table_definition.to_sql
206
+ create_sql << ") #{options[:options]}"
207
+ create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}"
208
+
209
+ execute create_sql
210
+
211
+ clobs.each do |clob_column|
212
+ execute "ALTER TABLE #{name+" ADD COLUMN "+clob_column.name.to_s+" clob"}"
213
+ execute "CREATE AUXILIARY TABLE #{name+"_"+clob_column.name.to_s+"_CD_"} IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]} STORES #{name} COLUMN "+clob_column.name.to_s
214
+ execute "CREATE UNIQUE INDEX #{name+"_"+clob_column.name.to_s+"_CD_"} ON #{name+"_"+clob_column.name.to_s+"_CD_"};"
215
+ end
216
+ else
217
+ super(name, options)
218
+ end
219
+ end
220
+
221
+ def replace_limit_offset!(sql, limit, offset)
222
+ if limit
223
+ limit = limit.to_i
224
+ if !offset
225
+ if limit == 1
226
+ sql << " FETCH FIRST ROW ONLY"
227
+ else
228
+ sql << " FETCH FIRST #{limit} ROWS ONLY"
229
+ end
230
+ else
231
+ offset = offset.to_i
232
+ sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
233
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
234
+ end
235
+ end
236
+ sql
237
+ end
238
+
239
+ def pk_and_sequence_for(table)
240
+ # In JDBC/DB2 side, only upcase names of table and column are handled.
241
+ keys = super(table.upcase)
242
+ if keys && keys[0]
243
+ # In ActiveRecord side, only downcase names of table and column are handled.
244
+ keys[0] = keys[0].downcase
245
+ end
246
+ keys
247
+ end
248
+
249
+ def quote_column_name(column_name)
250
+ column_name
251
+ end
252
+
253
+ def quote(value, column = nil) # :nodoc:
254
+ if column && column.respond_to?(:primary) && column.primary && column.klass != String
255
+ return value.to_i.to_s
256
+ end
257
+ if column && (column.type == :decimal || column.type == :integer) && value
258
+ return value.to_s
259
+ end
260
+ case value
261
+ when String
262
+ if column && column.type == :binary
263
+ "BLOB('#{quote_string(value)}')"
264
+ else
265
+ if zos? && column.type == :text
266
+ "'if_you_see_this_value_the_after_save_hook_in_db2_zos_adapter_went_wrong'"
267
+ else
268
+ "'#{quote_string(value)}'"
269
+ end
270
+ end
271
+ else super
272
+ end
273
+ end
274
+
275
+ def quote_string(string)
276
+ string.gsub(/'/, "''") # ' (for ruby-mode)
277
+ end
278
+
279
+ def quoted_true
280
+ '1'
281
+ end
282
+
283
+ def quoted_false
284
+ '0'
285
+ end
286
+
287
+ def reorg_table(table_name)
288
+ unless as400?
289
+ @connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
290
+ end
291
+ end
292
+
293
+ def recreate_database(name)
294
+ tables.each {|table| drop_table("#{db2_schema}.#{table}")}
295
+ end
296
+
297
+ def add_index(table_name, column_name, options = {})
298
+ if (!zos? || (table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s))
299
+ super
300
+ else
301
+ statement ="CREATE"
302
+ statement << " UNIQUE " if options[:unique]
303
+ statement << " INDEX "+"#{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
304
+
305
+ statement << " ON #{table_name}(#{column_name})"
306
+
307
+ execute statement
308
+ end
309
+ end
310
+
311
+
312
+ def remove_index(table_name, options = { })
313
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
314
+ end
315
+
316
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
317
+ # ...not supported on IBM i, so we raise in this case
318
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
319
+ if as400?
320
+ raise NotImplementedError, "rename_column is not supported on IBM i"
321
+ else
322
+ execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
323
+ reorg_table(table_name)
324
+ end
325
+ end
326
+
327
+ def change_column_null(table_name, column_name, null)
328
+ if null
329
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
330
+ else
331
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
332
+ end
333
+ reorg_table(table_name)
334
+ end
335
+
336
+ def change_column_default(table_name, column_name, default)
337
+ if default.nil?
338
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
339
+ else
340
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
341
+ end
342
+ reorg_table(table_name)
343
+ end
344
+
345
+ def change_column(table_name, column_name, type, options = {})
346
+ data_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
347
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
348
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
349
+ reorg_table(table_name)
350
+
351
+ if options.include?(:default) and options.include?(:null)
352
+ # which to run first?
353
+ if options[:null] or options[:default].nil?
354
+ change_column_null(table_name, column_name, options[:null])
355
+ change_column_default(table_name, column_name, options[:default])
356
+ else
357
+ change_column_default(table_name, column_name, options[:default])
358
+ change_column_null(table_name, column_name, options[:null])
359
+ end
360
+ elsif options.include?(:default)
361
+ change_column_default(table_name, column_name, options[:default])
362
+ elsif options.include?(:null)
363
+ change_column_null(table_name, column_name, options[:null])
364
+ end
365
+ end
366
+
367
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
368
+ def remove_column(table_name, column_name) #:nodoc:
369
+ sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
370
+
371
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
372
+ reorg_table(table_name)
373
+ end
374
+
375
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
376
+ def rename_table(name, new_name) #:nodoc:
377
+ execute "RENAME TABLE #{name} TO #{new_name}"
378
+ reorg_table(new_name)
379
+ end
380
+
381
+ def tables
382
+ @connection.tables(nil, db2_schema, nil, ["TABLE"])
383
+ end
384
+
385
+ # only record precision and scale for types that can set
386
+ # them via CREATE TABLE:
387
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
388
+ HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
389
+ HAVE_PRECISION = %w(DECIMAL NUMERIC)
390
+ HAVE_SCALE = %w(DECIMAL NUMERIC)
391
+
392
+ def columns(table_name, name = nil)
393
+ cols = @connection.columns(table_name, name, db2_schema)
394
+
395
+ if zos?
396
+ # Remove the mighty db2_generated_rowid_for_lobs from the list of columns
397
+ cols = cols.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
398
+ end
399
+ # scrub out sizing info when CREATE TABLE doesn't support it
400
+ # but JDBC reports it (doh!)
401
+ for col in cols
402
+ base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
403
+ col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
404
+ col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
405
+ #col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
406
+ end
407
+
408
+ cols
409
+ end
410
+
411
+ def jdbc_columns(table_name, name = nil)
412
+ columns(table_name, name)
413
+ end
414
+
415
+ def indexes(table_name, name = nil)
416
+ @connection.indexes(table_name, name, db2_schema)
417
+ end
418
+
419
+ def add_quotes(name)
420
+ return name unless name
421
+ %Q{"#{name}"}
422
+ end
423
+
424
+ def strip_quotes(str)
425
+ return str unless str
426
+ return str unless /^(["']).*\1$/ =~ str
427
+ str[1..-2]
428
+ end
429
+
430
+ def expand_double_quotes(name)
431
+ return name unless name && name['"']
432
+ name.gsub(/"/,'""')
433
+ end
434
+
435
+ def structure_dump #:nodoc:
436
+ definition=""
437
+ rs = @connection.connection.meta_data.getTables(nil,db2_schema.upcase,nil,["TABLE"].to_java(:string))
438
+ while rs.next
439
+ tname = rs.getString(3)
440
+ definition << "CREATE TABLE #{tname} (\n"
441
+ rs2 = @connection.connection.meta_data.getColumns(nil,db2_schema.upcase,tname,nil)
442
+ first_col = true
443
+ while rs2.next
444
+ col_name = add_quotes(rs2.getString(4));
445
+ default = ""
446
+ d1 = rs2.getString(13)
447
+ # IBM i (as400 toolbox driver) will return an empty string if there is no default
448
+ if @config[:url] =~ /^jdbc:as400:/
449
+ default = !d1.blank? ? " DEFAULT #{d1}" : ""
450
+ else
451
+ default = d1 ? " DEFAULT #{d1}" : ""
452
+ end
453
+
454
+ type = rs2.getString(6)
455
+ col_precision = rs2.getString(7)
456
+ col_scale = rs2.getString(9)
457
+ col_size = ""
458
+ if HAVE_SCALE.include?(type) and col_scale
459
+ col_size = "(#{col_precision},#{col_scale})"
460
+ elsif (HAVE_LIMIT + HAVE_PRECISION).include?(type) and col_precision
461
+ col_size = "(#{col_precision})"
462
+ end
463
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
464
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
465
+ " " +
466
+ type +
467
+ col_size +
468
+ "" +
469
+ nulling +
470
+ default
471
+ if !first_col
472
+ create_col_string = ",\n #{create_col_string}"
473
+ else
474
+ create_col_string = " #{create_col_string}"
475
+ end
476
+
477
+ definition << create_col_string
478
+
479
+ first_col = false
480
+ end
481
+ definition << ");\n\n"
482
+ end
483
+ definition
484
+ end
485
+
486
+ def zos?
487
+ @config[:driver] == "com.ibm.db2.jcc.DB2Driver"
488
+ end
489
+
490
+ private
491
+ def as400?
492
+ @config[:url] =~ /^jdbc:as400:/
493
+ end
494
+
495
+ def db2_schema
496
+ if @config[:schema].blank?
497
+ if as400?
498
+ # AS400 implementation takes schema from library name (last part of url)
499
+ schema = @config[:url].split('/').last.strip
500
+ (schema[-1..-1] == ";") ? schema.chop : schema
501
+ else
502
+ # LUW implementation uses schema name of username by default
503
+ @config[:username] or ENV['USER']
504
+ end
505
+ else
506
+ @config[:schema]
507
+ end
508
+ end
509
+ end
510
+ end