activerecord-jdbc-adapter 1.2.5 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +5 -1
  3. data/Appraisals +5 -5
  4. data/Gemfile +9 -1
  5. data/Gemfile.lock +44 -10
  6. data/History.txt +126 -2
  7. data/README.md +246 -0
  8. data/Rakefile +34 -25
  9. data/activerecord-jdbc-adapter.gemspec +1 -1
  10. data/gemfiles/rails23.gemfile +5 -3
  11. data/gemfiles/rails23.gemfile.lock +26 -18
  12. data/gemfiles/rails30.gemfile +4 -2
  13. data/gemfiles/rails30.gemfile.lock +16 -8
  14. data/gemfiles/rails31.gemfile +4 -2
  15. data/gemfiles/rails31.gemfile.lock +16 -9
  16. data/gemfiles/rails32.gemfile +4 -2
  17. data/gemfiles/rails32.gemfile.lock +15 -8
  18. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  19. data/lib/arel/visitors/sql_server.rb +3 -0
  20. data/lib/arjdbc.rb +3 -5
  21. data/lib/arjdbc/db2.rb +1 -0
  22. data/lib/arjdbc/db2/adapter.rb +302 -196
  23. data/lib/arjdbc/db2/connection_methods.rb +18 -0
  24. data/lib/arjdbc/derby/active_record_patch.rb +12 -0
  25. data/lib/arjdbc/derby/adapter.rb +180 -158
  26. data/lib/arjdbc/derby/connection_methods.rb +5 -1
  27. data/lib/arjdbc/firebird/adapter.rb +27 -19
  28. data/lib/arjdbc/h2/adapter.rb +162 -7
  29. data/lib/arjdbc/h2/connection_methods.rb +5 -1
  30. data/lib/arjdbc/hsqldb.rb +1 -1
  31. data/lib/arjdbc/hsqldb/adapter.rb +96 -61
  32. data/lib/arjdbc/hsqldb/connection_methods.rb +5 -1
  33. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  34. data/lib/arjdbc/informix/adapter.rb +56 -55
  35. data/lib/arjdbc/jdbc/adapter.rb +173 -86
  36. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  37. data/lib/arjdbc/jdbc/column.rb +28 -23
  38. data/lib/arjdbc/jdbc/connection.rb +10 -6
  39. data/lib/arjdbc/jdbc/driver.rb +13 -5
  40. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +21 -0
  41. data/lib/arjdbc/mssql.rb +1 -1
  42. data/lib/arjdbc/mssql/adapter.rb +51 -53
  43. data/lib/arjdbc/mssql/connection_methods.rb +8 -1
  44. data/lib/arjdbc/mysql.rb +1 -1
  45. data/lib/arjdbc/mysql/adapter.rb +186 -150
  46. data/lib/arjdbc/mysql/connection_methods.rb +9 -9
  47. data/lib/arjdbc/mysql/explain_support.rb +85 -0
  48. data/lib/arjdbc/oracle.rb +1 -1
  49. data/lib/arjdbc/oracle/adapter.rb +232 -125
  50. data/lib/arjdbc/oracle/connection_methods.rb +2 -2
  51. data/lib/arjdbc/postgresql.rb +1 -1
  52. data/lib/arjdbc/postgresql/adapter.rb +134 -86
  53. data/lib/arjdbc/postgresql/connection_methods.rb +6 -4
  54. data/lib/arjdbc/postgresql/explain_support.rb +55 -0
  55. data/lib/arjdbc/sqlite3.rb +1 -1
  56. data/lib/arjdbc/sqlite3/adapter.rb +176 -108
  57. data/lib/arjdbc/sqlite3/connection_methods.rb +5 -5
  58. data/lib/arjdbc/sqlite3/explain_support.rb +32 -0
  59. data/lib/arjdbc/sybase/adapter.rb +7 -6
  60. data/lib/arjdbc/version.rb +1 -1
  61. data/pom.xml +1 -1
  62. data/rakelib/02-test.rake +9 -11
  63. data/rakelib/rails.rake +18 -10
  64. data/src/java/arjdbc/db2/DB2Module.java +70 -0
  65. data/src/java/arjdbc/derby/DerbyModule.java +24 -5
  66. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +66 -0
  67. data/src/java/arjdbc/jdbc/AdapterJavaService.java +14 -7
  68. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +111 -89
  69. data/src/java/arjdbc/mysql/MySQLModule.java +79 -70
  70. data/src/java/arjdbc/oracle/OracleModule.java +74 -0
  71. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +5 -10
  72. data/src/java/arjdbc/sqlite3/SQLite3Module.java +77 -0
  73. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +127 -0
  74. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +25 -111
  75. data/src/java/arjdbc/util/QuotingUtils.java +104 -0
  76. data/test/abstract_db_create.rb +6 -6
  77. data/test/activerecord/connection_adapters/type_conversion_test.rb +2 -2
  78. data/test/assets/flowers.jpg +0 -0
  79. data/test/binary.rb +67 -0
  80. data/test/db/db2.rb +30 -7
  81. data/test/db/jdbc.rb +4 -2
  82. data/test/db/oracle.rb +18 -27
  83. data/test/db2_binary_test.rb +6 -0
  84. data/test/db2_serialize_test.rb +6 -0
  85. data/test/db2_simple_test.rb +20 -25
  86. data/test/db2_test.rb +71 -0
  87. data/test/derby_binary_test.rb +6 -0
  88. data/test/derby_migration_test.rb +42 -35
  89. data/test/derby_reset_column_information_test.rb +1 -0
  90. data/test/derby_row_locking_test.rb +17 -0
  91. data/test/derby_schema_dump_test.rb +9 -0
  92. data/test/derby_serialize_test.rb +6 -0
  93. data/test/derby_simple_test.rb +59 -17
  94. data/test/generic_jdbc_connection_test.rb +112 -5
  95. data/test/h2_binary_test.rb +6 -0
  96. data/test/h2_change_column_test.rb +1 -1
  97. data/test/h2_schema_dump_test.rb +25 -0
  98. data/test/h2_serialize_test.rb +6 -0
  99. data/test/h2_simple_test.rb +23 -9
  100. data/test/has_many_through.rb +18 -4
  101. data/test/hsqldb_binary_test.rb +6 -0
  102. data/test/hsqldb_schema_dump_test.rb +15 -0
  103. data/test/hsqldb_serialize_test.rb +6 -0
  104. data/test/hsqldb_simple_test.rb +1 -0
  105. data/test/informix_simple_test.rb +1 -1
  106. data/test/jdbc/db2.rb +23 -0
  107. data/test/jdbc/oracle.rb +23 -0
  108. data/test/jdbc_common.rb +3 -110
  109. data/test/jndi_callbacks_test.rb +0 -2
  110. data/test/jndi_test.rb +2 -0
  111. data/test/models/binary.rb +18 -0
  112. data/test/models/custom_pk_name.rb +1 -0
  113. data/test/models/data_types.rb +11 -2
  114. data/test/models/entry.rb +1 -1
  115. data/test/models/string_id.rb +2 -2
  116. data/test/models/thing.rb +1 -1
  117. data/test/models/topic.rb +32 -0
  118. data/test/mssql_legacy_types_test.rb +1 -1
  119. data/test/mssql_limit_offset_test.rb +13 -3
  120. data/test/mssql_serialize_test.rb +6 -0
  121. data/test/mysql_binary_test.rb +6 -0
  122. data/test/mysql_schema_dump_test.rb +220 -0
  123. data/test/mysql_serialize_test.rb +6 -0
  124. data/test/mysql_simple_test.rb +22 -2
  125. data/test/mysql_test.rb +93 -0
  126. data/test/oracle_binary_test.rb +6 -0
  127. data/test/oracle_limit_test.rb +2 -1
  128. data/test/oracle_serialize_test.rb +6 -0
  129. data/test/oracle_simple_test.rb +61 -0
  130. data/test/oracle_specific_test.rb +77 -26
  131. data/test/postgres_binary_test.rb +6 -0
  132. data/test/postgres_native_type_mapping_test.rb +12 -11
  133. data/test/postgres_nonseq_pkey_test.rb +1 -0
  134. data/test/postgres_reserved_test.rb +1 -0
  135. data/test/postgres_reset_column_information_test.rb +1 -0
  136. data/test/postgres_row_locking_test.rb +21 -0
  137. data/test/postgres_schema_dump_test.rb +88 -0
  138. data/test/postgres_schema_search_path_test.rb +1 -0
  139. data/test/postgres_simple_test.rb +62 -89
  140. data/test/postgres_table_alias_length_test.rb +1 -0
  141. data/test/postgres_test.rb +31 -0
  142. data/test/postgres_type_conversion_test.rb +16 -16
  143. data/test/row_locking.rb +69 -64
  144. data/test/schema_dump.rb +168 -0
  145. data/test/serialize.rb +277 -0
  146. data/test/simple.rb +326 -122
  147. data/test/sqlite3_serialize_test.rb +6 -0
  148. data/test/sqlite3_simple_test.rb +51 -84
  149. data/test/sqlite3_type_conversion_test.rb +101 -0
  150. data/test/test_helper.rb +224 -0
  151. metadata +325 -366
  152. data/README.rdoc +0 -214
  153. data/test/db/logger.rb +0 -3
  154. data/test/derby_multibyte_test.rb +0 -11
  155. data/test/mysql_info_test.rb +0 -123
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rake/testtask'
2
2
  require 'rake/clean'
3
- CLEAN.include 'derby*', 'test.db.*','test/reports', 'test.sqlite3','lib/**/*.jar','manifest.mf', '*.log'
3
+ CLEAN.include 'derby*', 'test.db.*','test/reports', 'test.sqlite3','lib/**/*.jar','manifest.mf', '*.log', 'target/*'
4
4
 
5
5
  require 'bundler/gem_helper'
6
6
  Bundler::GemHelper.install_tasks
@@ -14,46 +14,55 @@ task :default => [:jar, :test]
14
14
  task :build => :jar
15
15
  task :install => :jar
16
16
 
17
- ADAPTERS = %w[derby h2 hsqldb mssql mysql postgresql sqlite3].map {|a| "activerecord-jdbc#{a}-adapter" }
18
- DRIVERS = %w[derby h2 hsqldb jtds mysql postgres sqlite3].map {|a| "jdbc-#{a}" }
17
+ ADAPTERS = %w[derby h2 hsqldb mssql mysql postgresql sqlite3].map { |a| "activerecord-jdbc#{a}-adapter" }
18
+ DRIVERS = %w[derby h2 hsqldb jtds mysql postgres sqlite3].map { |a| "jdbc-#{a}" }
19
+ TARGETS = ( ADAPTERS + DRIVERS )
19
20
 
20
21
  def rake(*args)
21
22
  ruby "-S", "rake", *args
22
23
  end
23
24
 
24
- (ADAPTERS + DRIVERS).each do |adapter|
25
- namespace adapter do
26
-
25
+ TARGETS.each do |target|
26
+ namespace target do
27
27
  task :build do
28
- Dir.chdir(adapter) do
29
- rake "build"
30
- end
31
- cp FileList["#{adapter}/pkg/#{adapter}-*.gem"], "pkg"
28
+ Dir.chdir(target) { rake "build" }
29
+ cp FileList["#{target}/pkg/#{target}-*.gem"], "pkg"
32
30
  end
33
-
34
- # bundler handles install => build itself
35
31
  task :install do
36
- Dir.chdir(adapter) do
37
- rake "install"
38
- end
32
+ Dir.chdir(target) { rake "install" }
39
33
  end
40
-
41
34
  task :release do
42
- Dir.chdir(adapter) do
43
- rake "release"
44
- end
35
+ Dir.chdir(target) { rake "release" }
45
36
  end
46
37
  end
47
38
  end
48
39
 
49
- desc "Release all adapters"
50
- task "all:release" => ["release", *ADAPTERS.map { |f| "#{f}:release" }]
40
+ # DRIVERS
41
+
42
+ desc "Build drivers"
43
+ task "drivers:build" => DRIVERS.map { |name| "#{name}:build" }
44
+
45
+ desc "Install drivers"
46
+ task "drivers:install" => DRIVERS.map { |name| "#{name}:install" }
47
+
48
+ desc "Release drivers"
49
+ task "drivers:release" => DRIVERS.map { |name| "#{name}:release" }
50
+
51
+ # ADAPTERS
52
+
53
+ desc "Build adapters"
54
+ task "adapters:build" => [ 'build' ] + ADAPTERS.map { |name| "#{name}:build" }
55
+
56
+ desc "Install adapters"
57
+ task "adapters:install" => [ 'install' ] + ADAPTERS.map { |name| "#{name}:install" }
58
+
59
+ desc "Release adapters"
60
+ task "adapters:release" => [ 'release' ] + ADAPTERS.map { |name| "#{name}:release" }
51
61
 
52
- desc "Install all adapters"
53
- task "all:install" => ["install", *ADAPTERS.map { |f| "#{f}:install" }]
62
+ # ALL
54
63
 
55
- desc "Build all adapters"
56
- task "all:build" => ["build", *ADAPTERS.map { |f| "#{f}:build" }]
64
+ task "all:build" => [ 'build' ] + TARGETS.map { |name| "#{name}:build" }
65
+ task "all:install" => [ 'install' ] + TARGETS.map { |name| "#{name}:install" }
57
66
 
58
67
  task :filelist do
59
68
  puts FileList['pkg/**/*'].inspect
@@ -18,7 +18,7 @@ virtually any JDBC-compliant database with your JRuby on Rails application.}
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
- s.rdoc_options = ["--main", "README.rdoc", "-SHN", "-f", "darkfish"]
21
+ s.rdoc_options = ["--main", "README.md", "-SHN", "-f", "darkfish"]
22
22
  s.rubyforge_project = %q{jruby-extras}
23
23
  end
24
24
 
@@ -6,7 +6,9 @@ gem "jruby-openssl", :platform=>:jruby
6
6
  gem "appraisal"
7
7
  gem "rake", :require=>nil
8
8
  gem "test-unit", :group=>:test
9
- gem "mocha", :group=>:test
10
- gem "activerecord", "~> 2.3.14"
11
- gem "rails", "~> 2.3.14"
9
+ gem "mocha", :require=>nil, :group=>:test
10
+ gem "simplecov", :require=>nil, :group=>:test
11
+ gem "bcrypt-ruby", "~> 3.0.0", :require=>nil, :group=>:test
12
+ gem "activerecord", "~> 2.3.16"
13
+ gem "rails", "~> 2.3.16"
12
14
 
@@ -1,44 +1,52 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- actionmailer (2.3.14)
5
- actionpack (= 2.3.14)
6
- actionpack (2.3.14)
7
- activesupport (= 2.3.14)
4
+ actionmailer (2.3.16)
5
+ actionpack (= 2.3.16)
6
+ actionpack (2.3.16)
7
+ activesupport (= 2.3.16)
8
8
  rack (~> 1.1.0)
9
- activerecord (2.3.14)
10
- activesupport (= 2.3.14)
11
- activeresource (2.3.14)
12
- activesupport (= 2.3.14)
13
- activesupport (2.3.14)
9
+ activerecord (2.3.16)
10
+ activesupport (= 2.3.16)
11
+ activeresource (2.3.16)
12
+ activesupport (= 2.3.16)
13
+ activesupport (2.3.16)
14
14
  appraisal (0.5.1)
15
15
  bundler
16
16
  rake
17
+ bcrypt-ruby (3.0.1-java)
17
18
  bouncy-castle-java (1.5.0146.1)
18
19
  jruby-openssl (0.7.7)
19
20
  bouncy-castle-java (>= 1.5.0146.1)
20
21
  metaclass (0.0.1)
21
22
  mocha (0.11.4)
22
23
  metaclass (~> 0.0.1)
23
- rack (1.1.3)
24
- rails (2.3.14)
25
- actionmailer (= 2.3.14)
26
- actionpack (= 2.3.14)
27
- activerecord (= 2.3.14)
28
- activeresource (= 2.3.14)
29
- activesupport (= 2.3.14)
24
+ multi_json (1.5.0)
25
+ rack (1.1.5)
26
+ rails (2.3.16)
27
+ actionmailer (= 2.3.16)
28
+ actionpack (= 2.3.16)
29
+ activerecord (= 2.3.16)
30
+ activeresource (= 2.3.16)
31
+ activesupport (= 2.3.16)
30
32
  rake (>= 0.8.3)
31
33
  rake (0.9.2.2)
34
+ simplecov (0.7.1)
35
+ multi_json (~> 1.0)
36
+ simplecov-html (~> 0.7.1)
37
+ simplecov-html (0.7.1)
32
38
  test-unit (2.5.3)
33
39
 
34
40
  PLATFORMS
35
41
  java
36
42
 
37
43
  DEPENDENCIES
38
- activerecord (~> 2.3.14)
44
+ activerecord (~> 2.3.16)
39
45
  appraisal
46
+ bcrypt-ruby (~> 3.0.0)
40
47
  jruby-openssl
41
48
  mocha
42
- rails (~> 2.3.14)
49
+ rails (~> 2.3.16)
43
50
  rake
51
+ simplecov
44
52
  test-unit
@@ -6,6 +6,8 @@ gem "jruby-openssl", :platform=>:jruby
6
6
  gem "appraisal"
7
7
  gem "rake", :require=>nil
8
8
  gem "test-unit", :group=>:test
9
- gem "mocha", :group=>:test
10
- gem "activerecord", "~> 3.0.17"
9
+ gem "mocha", :require=>nil, :group=>:test
10
+ gem "simplecov", :require=>nil, :group=>:test
11
+ gem "bcrypt-ruby", "~> 3.0.0", :require=>nil, :group=>:test
12
+ gem "activerecord", "~> 3.0.20"
11
13
 
@@ -1,20 +1,21 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activemodel (3.0.17)
5
- activesupport (= 3.0.17)
4
+ activemodel (3.0.20)
5
+ activesupport (= 3.0.20)
6
6
  builder (~> 2.1.2)
7
7
  i18n (~> 0.5.0)
8
- activerecord (3.0.17)
9
- activemodel (= 3.0.17)
10
- activesupport (= 3.0.17)
8
+ activerecord (3.0.20)
9
+ activemodel (= 3.0.20)
10
+ activesupport (= 3.0.20)
11
11
  arel (~> 2.0.10)
12
12
  tzinfo (~> 0.3.23)
13
- activesupport (3.0.17)
13
+ activesupport (3.0.20)
14
14
  appraisal (0.5.1)
15
15
  bundler
16
16
  rake
17
17
  arel (2.0.10)
18
+ bcrypt-ruby (3.0.1-java)
18
19
  bouncy-castle-java (1.5.0146.1)
19
20
  builder (2.1.2)
20
21
  i18n (0.5.0)
@@ -23,17 +24,24 @@ GEM
23
24
  metaclass (0.0.1)
24
25
  mocha (0.11.4)
25
26
  metaclass (~> 0.0.1)
27
+ multi_json (1.5.0)
26
28
  rake (10.0.3)
29
+ simplecov (0.7.1)
30
+ multi_json (~> 1.0)
31
+ simplecov-html (~> 0.7.1)
32
+ simplecov-html (0.7.1)
27
33
  test-unit (2.5.3)
28
- tzinfo (0.3.33)
34
+ tzinfo (0.3.35)
29
35
 
30
36
  PLATFORMS
31
37
  java
32
38
 
33
39
  DEPENDENCIES
34
- activerecord (~> 3.0.17)
40
+ activerecord (~> 3.0.20)
35
41
  appraisal
42
+ bcrypt-ruby (~> 3.0.0)
36
43
  jruby-openssl
37
44
  mocha
38
45
  rake
46
+ simplecov
39
47
  test-unit
@@ -6,6 +6,8 @@ gem "jruby-openssl", :platform=>:jruby
6
6
  gem "appraisal"
7
7
  gem "rake", :require=>nil
8
8
  gem "test-unit", :group=>:test
9
- gem "mocha", :group=>:test
10
- gem "activerecord", "~> 3.1.8"
9
+ gem "mocha", :require=>nil, :group=>:test
10
+ gem "simplecov", :require=>nil, :group=>:test
11
+ gem "bcrypt-ruby", "~> 3.0.0", :require=>nil, :group=>:test
12
+ gem "activerecord", "~> 3.1.10"
11
13
 
@@ -1,23 +1,24 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activemodel (3.1.8)
5
- activesupport (= 3.1.8)
4
+ activemodel (3.1.10)
5
+ activesupport (= 3.1.10)
6
6
  builder (~> 3.0.0)
7
7
  i18n (~> 0.6)
8
- activerecord (3.1.8)
9
- activemodel (= 3.1.8)
10
- activesupport (= 3.1.8)
8
+ activerecord (3.1.10)
9
+ activemodel (= 3.1.10)
10
+ activesupport (= 3.1.10)
11
11
  arel (~> 2.2.3)
12
12
  tzinfo (~> 0.3.29)
13
- activesupport (3.1.8)
13
+ activesupport (3.1.10)
14
14
  multi_json (>= 1.0, < 1.3)
15
15
  appraisal (0.5.1)
16
16
  bundler
17
17
  rake
18
18
  arel (2.2.3)
19
+ bcrypt-ruby (3.0.1-java)
19
20
  bouncy-castle-java (1.5.0146.1)
20
- builder (3.0.0)
21
+ builder (3.0.4)
21
22
  i18n (0.6.1)
22
23
  jruby-openssl (0.7.7)
23
24
  bouncy-castle-java (>= 1.5.0146.1)
@@ -26,16 +27,22 @@ GEM
26
27
  metaclass (~> 0.0.1)
27
28
  multi_json (1.2.0)
28
29
  rake (10.0.3)
30
+ simplecov (0.7.1)
31
+ multi_json (~> 1.0)
32
+ simplecov-html (~> 0.7.1)
33
+ simplecov-html (0.7.1)
29
34
  test-unit (2.5.3)
30
- tzinfo (0.3.33)
35
+ tzinfo (0.3.35)
31
36
 
32
37
  PLATFORMS
33
38
  java
34
39
 
35
40
  DEPENDENCIES
36
- activerecord (~> 3.1.8)
41
+ activerecord (~> 3.1.10)
37
42
  appraisal
43
+ bcrypt-ruby (~> 3.0.0)
38
44
  jruby-openssl
39
45
  mocha
40
46
  rake
47
+ simplecov
41
48
  test-unit
@@ -6,6 +6,8 @@ gem "jruby-openssl", :platform=>:jruby
6
6
  gem "appraisal"
7
7
  gem "rake", :require=>nil
8
8
  gem "test-unit", :group=>:test
9
- gem "mocha", :group=>:test
10
- gem "activerecord", "~> 3.2.9"
9
+ gem "mocha", :require=>nil, :group=>:test
10
+ gem "simplecov", :require=>nil, :group=>:test
11
+ gem "bcrypt-ruby", "~> 3.0.0", :require=>nil, :group=>:test
12
+ gem "activerecord", "~> 3.2.11"
11
13
 
@@ -1,21 +1,22 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- activemodel (3.2.9)
5
- activesupport (= 3.2.9)
4
+ activemodel (3.2.11)
5
+ activesupport (= 3.2.11)
6
6
  builder (~> 3.0.0)
7
- activerecord (3.2.9)
8
- activemodel (= 3.2.9)
9
- activesupport (= 3.2.9)
7
+ activerecord (3.2.11)
8
+ activemodel (= 3.2.11)
9
+ activesupport (= 3.2.11)
10
10
  arel (~> 3.0.2)
11
11
  tzinfo (~> 0.3.29)
12
- activesupport (3.2.9)
12
+ activesupport (3.2.11)
13
13
  i18n (~> 0.6)
14
14
  multi_json (~> 1.0)
15
15
  appraisal (0.5.1)
16
16
  bundler
17
17
  rake
18
18
  arel (3.0.2)
19
+ bcrypt-ruby (3.0.1-java)
19
20
  bouncy-castle-java (1.5.0146.1)
20
21
  builder (3.0.4)
21
22
  i18n (0.6.1)
@@ -24,8 +25,12 @@ GEM
24
25
  metaclass (0.0.1)
25
26
  mocha (0.11.4)
26
27
  metaclass (~> 0.0.1)
27
- multi_json (1.3.7)
28
+ multi_json (1.5.0)
28
29
  rake (10.0.3)
30
+ simplecov (0.7.1)
31
+ multi_json (~> 1.0)
32
+ simplecov-html (~> 0.7.1)
33
+ simplecov-html (0.7.1)
29
34
  test-unit (2.5.3)
30
35
  tzinfo (0.3.35)
31
36
 
@@ -33,9 +38,11 @@ PLATFORMS
33
38
  java
34
39
 
35
40
  DEPENDENCIES
36
- activerecord (~> 3.2.9)
41
+ activerecord (~> 3.2.11)
37
42
  appraisal
43
+ bcrypt-ruby (~> 3.0.0)
38
44
  jruby-openssl
39
45
  mocha
40
46
  rake
47
+ simplecov
41
48
  test-unit
@@ -0,0 +1 @@
1
+ require 'arjdbc/db2'
@@ -15,6 +15,9 @@ module Arel
15
15
  # Need to mimic the subquery logic in ARel 1.x for select count with limit
16
16
  # See arel/engines/sql/compilers/mssql_compiler.rb for details
17
17
  def visit_Arel_Nodes_SelectStatement o
18
+ if !o.limit && o.offset
19
+ raise ActiveRecord::ActiveRecordError, "You must specify :limit with :offset."
20
+ end
18
21
  order = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
19
22
  if o.limit
20
23
  if select_count?(o)
@@ -7,16 +7,14 @@ if defined?(JRUBY_VERSION)
7
7
  else
8
8
  RAILS_CONNECTION_ADAPTERS = %w(jdbc)
9
9
  end
10
- if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
11
- require 'arjdbc/jdbc'
12
- end
13
10
  else
14
11
  require 'active_record'
15
- require 'arjdbc/jdbc'
16
12
  end
17
- rescue LoadError
13
+ rescue LoadError => e
18
14
  warn "activerecord-jdbc-adapter requires ActiveRecord at runtime"
15
+ raise e
19
16
  end
17
+ require 'arjdbc/jdbc'
20
18
  else
21
19
  warn "activerecord-jdbc-adapter is for use with JRuby only"
22
20
  end
@@ -1,2 +1,3 @@
1
1
  require 'arjdbc/jdbc'
2
2
  require 'arjdbc/db2/adapter'
3
+ require 'arjdbc/db2/connection_methods'
@@ -1,69 +1,87 @@
1
+ require 'arjdbc/jdbc/serialized_attributes_helper'
2
+
1
3
  module ArJdbc
2
4
  module DB2
5
+
6
+ # TODO kind of standard AR configuration option for this would be nice :
7
+ ADD_LOB_CALLBACK = true unless const_defined?(:ADD_LOB_CALLBACK) # :nodoc
8
+
9
+ @@_lob_callback_added = nil
10
+ def self.lob_callback_added? # :nodoc
11
+ @@_lob_callback_added
12
+ end
13
+
14
+ def self.lob_callback_added! # :nodoc
15
+ @@_lob_callback_added = true
16
+ end
17
+
3
18
  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
- if respond_to?(:unserializable_attribute?)
12
- value = value.to_yaml if unserializable_attribute?(c.name, c)
13
- else
14
- value = value.to_yaml if value.is_a?(Hash)
15
- end
16
- next if value.nil?
17
- connection.write_large_object(c.type == :binary, c.name, self.class.table_name, self.class.primary_key, quote_value(id), value)
18
- end
19
+ if ADD_LOB_CALLBACK && ! lob_callback_added?
20
+ ActiveRecord::Base.class_eval do
21
+ def after_save_with_db2_lob
22
+ lob_columns = self.class.columns.select { |c| c.sql_type =~ /blob|clob/i }
23
+ lob_columns.each do |column|
24
+ value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
25
+ next if value.nil? # already set NULL
26
+
27
+ connection.write_large_object(
28
+ column.type == :binary, column.name,
29
+ self.class.table_name,
30
+ self.class.primary_key,
31
+ quote_value(id), value
32
+ )
19
33
  end
20
34
  end
21
-
22
- ActiveRecord::Base.after_save :after_save_with_db2zos_blob
23
-
24
- @lob_callback_added = true
35
+ alias after_save_with_db2zos_blob after_save_with_db2_lob # <-compat
25
36
  end
37
+ # TODO this should be changed to :after_save_with_db2_lob :
38
+ ActiveRecord::Base.after_save :after_save_with_db2zos_blob # <-compat
39
+ lob_callback_added!
26
40
  end
27
41
  end
28
-
42
+
29
43
  def self.column_selector
30
- [ /(db2|as400|zos)/i,
31
- lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
44
+ [ /(db2|as400|zos)/i, lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
32
45
  end
33
46
 
34
47
  def self.jdbc_connection_class
35
48
  ::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
36
49
  end
37
50
 
51
+ def self.arel2_visitors(config)
52
+ require 'arel/visitors/db2'
53
+ { 'db2' => ::Arel::Visitors::DB2, 'as400' => ::Arel::Visitors::DB2 }
54
+ end
55
+
56
+ def adapter_name
57
+ 'DB2'
58
+ end
59
+
38
60
  NATIVE_DATABASE_TYPES = {
39
- :double => { :name => "double" },
40
- :bigint => { :name => "bigint" }
61
+ :double => { :name => "double" },
62
+ :bigint => { :name => "bigint" },
63
+ :string => { :name => "varchar", :limit => 255 },
64
+ :text => { :name => "clob" },
65
+ :date => { :name => "date" },
66
+ :binary => { :name => "blob" },
67
+ :boolean => { :name => "smallint" }, # no native boolean type
68
+ :xml => { :name => "xml" },
69
+ :decimal => { :name => "decimal" },
70
+ :char => { :name => "char" },
71
+ :decfloat => { :name => "decfloat" },
72
+ #:rowid => { :name => "rowid" }, # supported datatype on z/OS and i/5
73
+ #:graphic => { :name => "graphic", :limit => 1 },
74
+ #:vargraphic => { :name => "vargraphic", :limit => 1 },
75
+ # TODO datetime / timestamp / time mapping
41
76
  }
42
77
 
43
78
  def native_database_types
44
79
  super.merge(NATIVE_DATABASE_TYPES)
45
80
  end
46
81
 
47
- def explain(query, *binds)
48
- # TODO: Explain this!
49
- end
50
-
51
- def prefetch_primary_key?(table_name = nil)
52
- # TRUE if the table has no identity column
53
- names = table_name.upcase.split(".")
54
- sql = "SELECT 1 FROM SYSCAT.COLUMNS WHERE IDENTITY = 'Y' "
55
- sql += "AND TABSCHEMA = '#{names.first}' " if names.size == 2
56
- sql += "AND TABNAME = '#{names.last}'"
57
- select_one(sql).nil?
58
- end
59
-
60
- def next_sequence_value(sequence_name)
61
- select_value("select next value for #{sequence_name} from sysibm.sysdummy1")
62
- end
63
-
64
82
  module Column
65
83
  def type_cast(value)
66
- return nil if value.nil? || value =~ /^\s*null\s*$/i
84
+ return nil if value.nil? || value == 'NULL' || value =~ /^\s*NULL\s*$/i
67
85
  case type
68
86
  when :string then value
69
87
  when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
@@ -93,6 +111,7 @@ module ArJdbc
93
111
  def self.cast_to_date_or_time(value)
94
112
  return value if value.is_a? Date
95
113
  return nil if value.blank?
114
+ # https://github.com/jruby/activerecord-jdbc-adapter/commit/c225126e025df2e98ba3386c67e2a5bc5e5a73e6
96
115
  return Time.now if value =~ /^CURRENT/
97
116
  guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
98
117
  rescue
@@ -110,17 +129,30 @@ module ArJdbc
110
129
  end
111
130
 
112
131
  def self.guess_date_or_time(value)
113
- (value.hour == 0 and value.min == 0 and value.sec == 0) ?
114
- Date.new(value.year, value.month, value.day) : value
132
+ return value if value.is_a? Date
133
+ ( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
134
+ Date.new(value.year, value.month, value.day) : value
115
135
  end
116
136
 
117
137
  private
118
138
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
119
139
  def simplified_type(field_type)
120
140
  case field_type
121
- when /^decimal\(1\)$/i then :boolean
122
- when /^real/i then :float
123
- when /^timestamp/i then :datetime
141
+ when /^decimal\(1\)$/i then :boolean
142
+ when /smallint|boolean/i then :boolean
143
+ when /^real|double/i then :float
144
+ when /int|serial/i then :integer
145
+ when /numeric|decfloat/i then :decimal
146
+ when /timestamp/i then :timestamp
147
+ when /datetime/i then :datetime
148
+ when /time/i then :time
149
+ when /date/i then :date
150
+ when /clob/i then :text
151
+ when /for bit data/i then :binary
152
+ when /xml/i then :xml
153
+ #when /vargraphic/i then :vargraphic
154
+ #when /graphic/i then :graphic
155
+ #when /rowid/i then :rowid # rowid is a supported datatype on z/OS and i/5
124
156
  else
125
157
  super
126
158
  end
@@ -137,15 +169,18 @@ module ArJdbc
137
169
  value
138
170
  end
139
171
  end
172
+
173
+ def prefetch_primary_key?(table_name = nil)
174
+ # TRUE if the table has no identity column
175
+ names = table_name.upcase.split(".")
176
+ sql = "SELECT 1 FROM SYSCAT.COLUMNS WHERE IDENTITY = 'Y' "
177
+ sql += "AND TABSCHEMA = '#{names.first}' " if names.size == 2
178
+ sql += "AND TABNAME = '#{names.last}'"
179
+ select_one(sql).nil?
180
+ end
140
181
 
141
- def _execute(sql, name = nil)
142
- if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
143
- @connection.execute_query(sql)
144
- elsif ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
145
- (@connection.execute_insert(sql) or last_insert_id(sql)).to_i
146
- else
147
- @connection.execute_update(sql)
148
- end
182
+ def next_sequence_value(sequence_name)
183
+ select_value("SELECT NEXT VALUE FOR #{sequence_name} FROM sysibm.sysdummy1")
149
184
  end
150
185
 
151
186
  # holy moly batman! all this to tell AS400 "yes i am sure"
@@ -155,108 +190,93 @@ module ArJdbc
155
190
  @connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
156
191
  rescue Exception => e
157
192
  raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
158
- "Do you have authority to do this?\n\n" + e.to_s
193
+ "Do you have authority to do this?\n\n" + e.to_s
159
194
  end
160
195
 
161
- r = execute sql
196
+ result = execute sql
162
197
 
163
198
  begin
164
199
  @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
165
200
  @connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
166
201
  rescue Exception => e
167
202
  raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
168
- "Do you have authority to do this?\n\n" + e.to_s
203
+ "Do you have authority to do this?\n\n" + e.to_s
169
204
  end
170
- r
205
+ result
171
206
  end
172
207
 
208
+ def _execute(sql, name = nil)
209
+ if self.class.select?(sql)
210
+ @connection.execute_query(sql)
211
+ elsif self.class.insert?(sql)
212
+ (@connection.execute_insert(sql) or last_insert_id(sql)).to_i
213
+ else
214
+ @connection.execute_update(sql)
215
+ end
216
+ end
217
+
173
218
  def last_insert_id(sql)
174
219
  table_name = sql.split(/\s/)[2]
175
- result = select(ActiveRecord::Base.send(:sanitize_sql, %[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}], nil))
220
+ result = select(ActiveRecord::Base.send(:sanitize_sql, %[SELECT IDENTITY_VAL_LOCAL() AS last_insert_id FROM #{table_name}], nil))
176
221
  result.last['last_insert_id']
177
222
  end
178
-
179
- def modify_types(tp)
180
- tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
181
- tp[:string][:limit] = 255
182
- tp[:integer][:limit] = nil
183
- tp[:boolean] = {:name => "decimal(1)"}
184
- tp
185
- end
186
-
187
- def type_to_sql(type, limit = nil, precision = nil, scale = nil)
188
- limit = nil if type.to_sym == :integer
189
- super(type, limit, precision, scale)
190
- end
191
-
192
- def adapter_name
193
- 'DB2'
194
- end
195
-
196
- def self.arel2_visitors(config)
197
- require 'arel/visitors/db2'
198
- {}.tap {|v| %w(db2 as400).each {|a| v[a] = ::Arel::Visitors::DB2 } }
199
- end
200
-
201
- def add_limit_offset!(sql, options)
202
- replace_limit_offset!(sql, options[:limit], options[:offset])
203
- end
204
-
205
-
223
+
206
224
  def create_table(name, options = {}) #:nodoc:
207
225
  if zos?
208
- table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
209
-
210
- table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(name)) unless options[:id] == false
211
-
212
- yield table_definition
213
-
214
- # Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
215
- # First: Save them for later in Array "clobs"
216
- clobs =table_definition.columns.select { |x| x.type == "text" }
217
-
218
- # Second: and delete them from the original Colums-Array
219
- table_definition.columns.delete_if { |x| x.type=="text" }
226
+ zos_create_table(name, options)
227
+ else
228
+ super(name, options)
229
+ end
230
+ end
231
+
232
+ def zos_create_table(name, options = {}) #:nodoc:
233
+ table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(self)
234
+ table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(name)) unless options[:id] == false
220
235
 
221
- if options[:force] && table_exists?(name)
222
- super.drop_table(name, options)
223
- end
236
+ yield table_definition
224
237
 
225
- create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
226
- create_sql << "#{quote_table_name(name)} ("
227
- create_sql << table_definition.to_sql
228
- create_sql << ") #{options[:options]}"
229
- create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}" if @config[:database] && @config[:tablespace]
238
+ # Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
239
+ # First: Save them for later in Array "clobs"
240
+ clobs = table_definition.columns.select { |x| x.type.to_s == "text" }
241
+ # Second: and delete them from the original Colums-Array
242
+ table_definition.columns.delete_if { |x| x.type.to_s == "text" }
230
243
 
231
- execute create_sql
244
+ drop_table(name, options) if options[:force] && table_exists?(name)
232
245
 
233
- clobs.each do |clob_column|
234
- execute "ALTER TABLE #{name+" ADD COLUMN "+clob_column.name.to_s+" clob"}"
235
- 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
236
- execute "CREATE UNIQUE INDEX #{name+"_"+clob_column.name.to_s+"_CD_"} ON #{name+"_"+clob_column.name.to_s+"_CD_"};"
237
- end
246
+ create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
247
+ create_sql << "#{quote_table_name(name)} ("
248
+ create_sql << table_definition.to_sql
249
+ create_sql << ") #{options[:options]}"
250
+ if @config[:database] && @config[:tablespace]
251
+ in_db_table_space = " IN #{@config[:database]}.#{@config[:tablespace]}"
238
252
  else
239
- super(name, options)
253
+ in_db_table_space = ''
240
254
  end
241
- end
242
-
243
- def replace_limit_offset!(sql, limit, offset)
244
- if limit
245
- limit = limit.to_i
246
- if !offset
247
- if limit == 1
248
- sql << " FETCH FIRST ROW ONLY"
249
- else
250
- sql << " FETCH FIRST #{limit} ROWS ONLY"
251
- end
255
+ create_sql << in_db_table_space
256
+
257
+ execute create_sql
258
+
259
+ # Table definition is complete only when a unique index is created on the primary_key column for DB2 V8 on zOS
260
+ # create index on id column if options[:id] is nil or id ==true
261
+ # else check if options[:primary_key]is not nil then create an unique index on that column
262
+ # TODO someone on Z/OS should test this out - also not needed for V9 ?
263
+ #primary_column = options[:id] == true ? 'id' : options[:primary_key]
264
+ #add_index(name, (primary_column || 'id').to_s, :unique => true)
265
+
266
+ clobs.each do |clob_column|
267
+ column_name = clob_column.name.to_s
268
+ execute "ALTER TABLE #{name + ' ADD COLUMN ' + column_name + ' clob'}"
269
+ clob_table_name = name + '_' + column_name + '_CD_'
270
+ if @config[:database] && @config[:lob_tablespaces]
271
+ in_lob_table_space = " IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]}"
252
272
  else
253
- offset = offset.to_i
254
- sql.sub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
255
- sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
273
+ in_lob_table_space = ''
256
274
  end
275
+ execute "CREATE AUXILIARY TABLE #{clob_table_name} #{in_lob_table_space} STORES #{name} COLUMN #{column_name}"
276
+ execute "CREATE UNIQUE INDEX #{clob_table_name} ON #{clob_table_name};"
257
277
  end
258
- sql
259
278
  end
279
+ private :zos_create_table
260
280
 
261
281
  def pk_and_sequence_for(table)
262
282
  # In JDBC/DB2 side, only upcase names of table and column are handled.
@@ -268,74 +288,147 @@ module ArJdbc
268
288
  keys
269
289
  end
270
290
 
271
- def quote_column_name(column_name)
272
- column_name.to_s
273
- end
274
-
291
+ # Properly quotes the various data types.
292
+ # +value+ contains the data, +column+ is optional and contains info on the field
275
293
  def quote(value, column = nil) # :nodoc:
276
- if column && column.respond_to?(:primary) && column.primary && column.klass != String
277
- return value.to_i.to_s
278
- end
279
- if column && (column.type == :decimal || column.type == :integer) && value
280
- return value.to_s
294
+ return value.quoted_id if value.respond_to?(:quoted_id)
295
+
296
+ if column
297
+ if column.respond_to?(:primary) && column.primary && column.klass != String
298
+ return value.to_i.to_s
299
+ end
300
+ if value && (column.type.to_sym == :decimal || column.type.to_sym == :integer)
301
+ return value.to_s
302
+ end
281
303
  end
304
+
305
+ column_type = column && column.type.to_sym
306
+
282
307
  case value
283
- when String
284
- if column && column.type == :binary
285
- "BLOB('#{quote_string(value)}')"
308
+ when nil then "NULL"
309
+ when Numeric # IBM_DB doesn't accept quotes on numeric types
310
+ # if the column type is text or string, return the quote value
311
+ if column_type == :text || column_type == :string
312
+ "'#{value}'"
286
313
  else
287
- if zos? && column.type == :text
288
- "'if_you_see_this_value_the_after_save_hook_in_db2_zos_adapter_went_wrong'"
314
+ value.to_s
315
+ end
316
+ when String, ActiveSupport::Multibyte::Chars
317
+ if column_type == :binary && !(column.sql_type =~ /for bit data/i)
318
+ if ArJdbc::DB2.lob_callback_added?
319
+ "NULL" # '@@@IBMBINARY@@@'"
320
+ else
321
+ "BLOB('#{quote_string(value)}')"
322
+ end
323
+ elsif column && column.sql_type =~ /clob/ # :text
324
+ if ArJdbc::DB2.lob_callback_added?
325
+ "NULL" # "'@@@IBMTEXT@@@'"
289
326
  else
290
327
  "'#{quote_string(value)}'"
291
328
  end
329
+ elsif column_type == :xml
330
+ "#{value}" # "'<ibm>@@@IBMXML@@@</ibm>'"
331
+ else
332
+ "'#{quote_string(value)}'"
292
333
  end
334
+ when Symbol then "'#{quote_string(value.to_s)}'"
293
335
  else super
294
336
  end
295
337
  end
296
338
 
297
- def quote_string(string)
298
- string.gsub(/'/, "''") # ' (for ruby-mode)
339
+ def quote_column_name(column_name)
340
+ column_name.to_s
299
341
  end
300
-
301
- def quoted_true
302
- '1'
342
+
343
+ def modify_types(types)
344
+ super(types)
345
+ types[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
346
+ types[:string][:limit] = 255
347
+ types[:integer][:limit] = nil
348
+ types[:boolean] = {:name => "decimal(1)"}
349
+ types
303
350
  end
304
351
 
305
- def quoted_false
306
- '0'
352
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
353
+ limit = nil if type.to_sym == :integer
354
+ super(type, limit, precision, scale)
307
355
  end
308
356
 
357
+ def add_limit_offset!(sql, options)
358
+ replace_limit_offset!(sql, options[:limit], options[:offset])
359
+ end
360
+
361
+ def add_column_options!(sql, options) # :nodoc:
362
+ # handle case of defaults for CLOB columns,
363
+ # which might get incorrect if we write LOBs in the after_save callback
364
+ if options_include_default?(options)
365
+ column = options[:column]
366
+ if column && column.type == :text
367
+ sql << " DEFAULT #{quote(options.delete(:default))}"
368
+ end
369
+ if column && column.type == :binary
370
+ # quoting required for the default value of a column :
371
+ value = options.delete(:default)
372
+ # DB2 z/OS only allows NULL or "" (empty) string as DEFAULT value
373
+ # for a BLOB column. non-empty string and non-NULL, return error!
374
+ if value.nil?
375
+ sql_value = "NULL"
376
+ else
377
+ sql_value = zos? ? "#{value}" : "BLOB('#{quote_string(value)}'"
378
+ end
379
+ sql << " DEFAULT #{sql_value}"
380
+ end
381
+ end
382
+ super
383
+ end
384
+
385
+ def replace_limit_offset!(sql, limit, offset)
386
+ if limit
387
+ limit = limit.to_i
388
+ if !offset
389
+ if limit == 1
390
+ sql << " FETCH FIRST ROW ONLY"
391
+ else
392
+ sql << " FETCH FIRST #{limit} ROWS ONLY"
393
+ end
394
+ else
395
+ offset = offset.to_i
396
+ sql.sub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
397
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
398
+ end
399
+ end
400
+ sql
401
+ end
402
+
309
403
  def reorg_table(table_name)
310
404
  unless as400?
311
405
  @connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
312
406
  end
313
407
  end
408
+ private :reorg_table
314
409
 
315
410
  def runstats_for_table(tablename, priority=10)
316
411
  @connection.execute_update "call sysproc.admin_cmd('RUNSTATS ON TABLE #{tablename} WITH DISTRIBUTION AND DETAILED INDEXES ALL UTIL_IMPACT_PRIORITY #{priority}')"
317
412
  end
318
413
 
319
414
  def recreate_database(name, options = {})
320
- tables.each {|table| drop_table("#{db2_schema}.#{table}")}
415
+ tables.each { |table| drop_table("#{db2_schema}.#{table}") }
321
416
  end
322
417
 
323
418
  def add_index(table_name, column_name, options = {})
324
- if (!zos? || (table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s))
419
+ if ! zos? || ( table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s )
325
420
  column_name = column_name.to_s if column_name.is_a?(Symbol)
326
421
  super
327
422
  else
328
- statement ="CREATE"
329
- statement << " UNIQUE " if options[:unique]
330
- statement << " INDEX "+"#{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
331
-
423
+ statement = 'CREATE'
424
+ statement << ' UNIQUE ' if options[:unique]
425
+ statement << " INDEX #{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
332
426
  statement << " ON #{table_name}(#{column_name})"
333
-
427
+
334
428
  execute statement
335
429
  end
336
430
  end
337
431
 
338
-
339
432
  def remove_index(table_name, options = { })
340
433
  execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
341
434
  end
@@ -392,12 +485,13 @@ module ArJdbc
392
485
  change_column_null(table_name, column_name, options[:null])
393
486
  end
394
487
  end
395
-
488
+
396
489
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
397
- def remove_column(table_name, column_name) #:nodoc:
398
- sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
399
-
400
- as400? ? execute_and_auto_confirm(sql) : execute(sql)
490
+ def remove_column(table_name, *column_names) #:nodoc:
491
+ for column_name in column_names.flatten
492
+ sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
493
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
494
+ end
401
495
  reorg_table(table_name)
402
496
  end
403
497
 
@@ -406,35 +500,34 @@ module ArJdbc
406
500
  execute "RENAME TABLE #{name} TO #{new_name}"
407
501
  reorg_table(new_name)
408
502
  end
409
-
503
+
410
504
  def tables
411
505
  @connection.tables(nil, db2_schema, nil, ["TABLE"])
412
506
  end
413
507
 
414
- # only record precision and scale for types that can set
415
- # them via CREATE TABLE:
508
+ # only record precision and scale for types that can set them via CREATE TABLE:
416
509
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
417
510
  HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
418
511
  HAVE_PRECISION = %w(DECIMAL NUMERIC)
419
512
  HAVE_SCALE = %w(DECIMAL NUMERIC)
420
513
 
421
514
  def columns(table_name, name = nil)
422
- cols = @connection.columns(table_name, name, db2_schema)
515
+ columns = @connection.columns(table_name.to_s, name, db2_schema)
423
516
 
424
517
  if zos?
425
518
  # Remove the mighty db2_generated_rowid_for_lobs from the list of columns
426
- cols = cols.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
519
+ columns = columns.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
427
520
  end
428
521
  # scrub out sizing info when CREATE TABLE doesn't support it
429
522
  # but JDBC reports it (doh!)
430
- for col in cols
431
- base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
432
- col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
433
- col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
434
- #col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
523
+ for column in columns
524
+ base_sql_type = column.sql_type.sub(/\(.*/, "").upcase
525
+ column.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
526
+ column.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
527
+ #column.scale = nil unless HAVE_SCALE.include?(base_sql_type)
435
528
  end
436
529
 
437
- cols
530
+ columns
438
531
  end
439
532
 
440
533
  def jdbc_columns(table_name, name = nil)
@@ -462,9 +555,9 @@ module ArJdbc
462
555
  end
463
556
 
464
557
  def structure_dump #:nodoc:
465
- definition=""
466
558
  schema_name = db2_schema.upcase if db2_schema.present?
467
- rs = @connection.connection.meta_data.getTables(nil,schema_name,nil,["TABLE"].to_java(:string))
559
+ rs = @connection.connection.meta_data.getTables(nil, schema_name, nil, ["TABLE"].to_java(:string))
560
+ definition = ''
468
561
  while rs.next
469
562
  tname = rs.getString(3)
470
563
  definition << "CREATE TABLE #{tname} (\n"
@@ -527,34 +620,47 @@ module ArJdbc
527
620
  end
528
621
  definition
529
622
  end
530
-
623
+
624
+ DRIVER_NAME = 'com.ibm.db2.jcc.DB2Driver'.freeze
625
+
531
626
  def zos?
532
- @config[:url] =~ /^jdbc:db2j:net:/ && @config[:driver] == "com.ibm.db2.jcc.DB2Driver"
627
+ return @zos unless @zos.nil?
628
+ @zos =
629
+ if url = @config[:url]
630
+ !!( url =~ /^jdbc:db2j:net:/ && @config[:driver] == DRIVER_NAME )
631
+ else
632
+ nil
633
+ end
533
634
  end
534
-
535
- private
635
+
536
636
  def as400?
537
- @config[:url] =~ /^jdbc:as400:/
637
+ return @as400 unless @as400.nil?
638
+ @as400 =
639
+ if url = @config[:url]
640
+ !!( url =~ /^jdbc:as400:/ )
641
+ else
642
+ nil
643
+ end
538
644
  end
539
645
 
646
+ private
647
+
540
648
  def db2_schema
541
- if @config[:schema].blank?
542
- if as400?
543
- # AS400 implementation takes schema from library name (last part of url)
544
- schema = @config[:url].split('/').last.strip
545
- (schema[-1..-1] == ";") ? schema.chop : schema
546
- elsif @config[:username].present?
547
- # LUW implementation uses schema name of username by default
548
- @config[:username]
649
+ return @db2_schema unless @db2_schema.nil?
650
+ @db2_schema =
651
+ if @config[:schema].present?
652
+ @config[:schema]
549
653
  elsif @config[:jndi].present?
550
- # let jndi worry about schema
551
- nil
654
+ nil # let JNDI worry about schema
655
+ elsif as400?
656
+ # AS400 implementation takes schema from library name (last part of URL)
657
+ # jdbc:as400://localhost/schema;naming=system;libraries=lib1,lib2
658
+ @config[:url].split('/').last.split(';').first.strip
552
659
  else
553
- ENV['USER']
660
+ # LUW implementation uses schema name of username by default
661
+ @config[:username].presence || ENV['USER']
554
662
  end
555
- else
556
- @config[:schema]
557
- end
558
663
  end
664
+
559
665
  end
560
666
  end