intentmedia-activerecord-jdbc-adapter 1.1.1.1

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 (177) hide show
  1. data/History.txt +404 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.txt +181 -0
  4. data/Rakefile +10 -0
  5. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  6. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  7. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  8. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  9. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  10. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  11. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  12. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  13. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  14. data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
  15. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  17. data/lib/activerecord-jdbc-adapter.rb +8 -0
  18. data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
  19. data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
  20. data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
  21. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +15 -0
  22. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
  23. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +46 -0
  24. data/lib/arel/visitors/compat.rb +13 -0
  25. data/lib/arel/visitors/db2.rb +17 -0
  26. data/lib/arel/visitors/derby.rb +21 -0
  27. data/lib/arel/visitors/hsqldb.rb +26 -0
  28. data/lib/arel/visitors/sql_server.rb +46 -0
  29. data/lib/arjdbc.rb +29 -0
  30. data/lib/arjdbc/db2.rb +2 -0
  31. data/lib/arjdbc/db2/adapter.rb +413 -0
  32. data/lib/arjdbc/derby.rb +7 -0
  33. data/lib/arjdbc/derby/adapter.rb +348 -0
  34. data/lib/arjdbc/derby/connection_methods.rb +18 -0
  35. data/lib/arjdbc/discover.rb +92 -0
  36. data/lib/arjdbc/firebird.rb +2 -0
  37. data/lib/arjdbc/firebird/adapter.rb +131 -0
  38. data/lib/arjdbc/h2.rb +4 -0
  39. data/lib/arjdbc/h2/adapter.rb +36 -0
  40. data/lib/arjdbc/h2/connection_methods.rb +12 -0
  41. data/lib/arjdbc/hsqldb.rb +4 -0
  42. data/lib/arjdbc/hsqldb/adapter.rb +184 -0
  43. data/lib/arjdbc/hsqldb/connection_methods.rb +14 -0
  44. data/lib/arjdbc/informix.rb +3 -0
  45. data/lib/arjdbc/informix/adapter.rb +138 -0
  46. data/lib/arjdbc/informix/connection_methods.rb +10 -0
  47. data/lib/arjdbc/jdbc.rb +2 -0
  48. data/lib/arjdbc/jdbc/adapter.rb +285 -0
  49. data/lib/arjdbc/jdbc/callbacks.rb +44 -0
  50. data/lib/arjdbc/jdbc/column.rb +38 -0
  51. data/lib/arjdbc/jdbc/compatibility.rb +51 -0
  52. data/lib/arjdbc/jdbc/connection.rb +128 -0
  53. data/lib/arjdbc/jdbc/connection_methods.rb +16 -0
  54. data/lib/arjdbc/jdbc/core_ext.rb +24 -0
  55. data/lib/arjdbc/jdbc/discover.rb +18 -0
  56. data/lib/arjdbc/jdbc/driver.rb +44 -0
  57. data/lib/arjdbc/jdbc/extension.rb +47 -0
  58. data/lib/arjdbc/jdbc/java.rb +14 -0
  59. data/lib/arjdbc/jdbc/jdbc.rake +127 -0
  60. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +87 -0
  61. data/lib/arjdbc/jdbc/quoted_primary_key.rb +28 -0
  62. data/lib/arjdbc/jdbc/railtie.rb +9 -0
  63. data/lib/arjdbc/jdbc/rake_tasks.rb +10 -0
  64. data/lib/arjdbc/jdbc/require_driver.rb +16 -0
  65. data/lib/arjdbc/jdbc/type_converter.rb +127 -0
  66. data/lib/arjdbc/mimer.rb +2 -0
  67. data/lib/arjdbc/mimer/adapter.rb +142 -0
  68. data/lib/arjdbc/mssql.rb +4 -0
  69. data/lib/arjdbc/mssql/adapter.rb +472 -0
  70. data/lib/arjdbc/mssql/connection_methods.rb +30 -0
  71. data/lib/arjdbc/mssql/limit_helpers.rb +92 -0
  72. data/lib/arjdbc/mssql/tsql_helper.rb +61 -0
  73. data/lib/arjdbc/mysql.rb +4 -0
  74. data/lib/arjdbc/mysql/adapter.rb +416 -0
  75. data/lib/arjdbc/mysql/connection_methods.rb +27 -0
  76. data/lib/arjdbc/oracle.rb +3 -0
  77. data/lib/arjdbc/oracle/adapter.rb +412 -0
  78. data/lib/arjdbc/oracle/connection_methods.rb +11 -0
  79. data/lib/arjdbc/postgresql.rb +4 -0
  80. data/lib/arjdbc/postgresql/adapter.rb +579 -0
  81. data/lib/arjdbc/postgresql/connection_methods.rb +21 -0
  82. data/lib/arjdbc/sqlite3.rb +4 -0
  83. data/lib/arjdbc/sqlite3/adapter.rb +381 -0
  84. data/lib/arjdbc/sqlite3/connection_methods.rb +34 -0
  85. data/lib/arjdbc/sybase.rb +2 -0
  86. data/lib/arjdbc/sybase/adapter.rb +46 -0
  87. data/lib/arjdbc/version.rb +8 -0
  88. data/lib/generators/jdbc/jdbc_generator.rb +9 -0
  89. data/lib/jdbc_adapter.rb +2 -0
  90. data/lib/jdbc_adapter/rake_tasks.rb +3 -0
  91. data/lib/jdbc_adapter/version.rb +3 -0
  92. data/lib/pg.rb +26 -0
  93. data/rails_generators/jdbc_generator.rb +15 -0
  94. data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
  95. data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
  96. data/rakelib/compile.rake +25 -0
  97. data/rakelib/db.rake +19 -0
  98. data/rakelib/package.rake +91 -0
  99. data/rakelib/rails.rake +41 -0
  100. data/rakelib/test.rake +81 -0
  101. data/src/java/arjdbc/derby/DerbyModule.java +322 -0
  102. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +70 -0
  103. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +74 -0
  104. data/src/java/arjdbc/jdbc/AdapterJavaService.java +66 -0
  105. data/src/java/arjdbc/jdbc/JdbcConnectionFactory.java +36 -0
  106. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1305 -0
  107. data/src/java/arjdbc/jdbc/SQLBlock.java +48 -0
  108. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +127 -0
  109. data/src/java/arjdbc/mysql/MySQLModule.java +134 -0
  110. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +87 -0
  111. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +85 -0
  112. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +57 -0
  113. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +64 -0
  114. data/test/abstract_db_create.rb +124 -0
  115. data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
  116. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
  117. data/test/db/db2.rb +11 -0
  118. data/test/db/derby.rb +12 -0
  119. data/test/db/h2.rb +11 -0
  120. data/test/db/hsqldb.rb +13 -0
  121. data/test/db/informix.rb +11 -0
  122. data/test/db/jdbc.rb +11 -0
  123. data/test/db/jndi_config.rb +40 -0
  124. data/test/db/logger.rb +3 -0
  125. data/test/db/mssql.rb +9 -0
  126. data/test/db/mysql.rb +10 -0
  127. data/test/db/oracle.rb +34 -0
  128. data/test/db/postgres.rb +9 -0
  129. data/test/db/sqlite3.rb +11 -0
  130. data/test/db2_simple_test.rb +66 -0
  131. data/test/derby_migration_test.rb +68 -0
  132. data/test/derby_multibyte_test.rb +12 -0
  133. data/test/derby_simple_test.rb +99 -0
  134. data/test/generic_jdbc_connection_test.rb +29 -0
  135. data/test/h2_simple_test.rb +41 -0
  136. data/test/has_many_through.rb +79 -0
  137. data/test/helper.rb +5 -0
  138. data/test/hsqldb_simple_test.rb +6 -0
  139. data/test/informix_simple_test.rb +48 -0
  140. data/test/jdbc_common.rb +25 -0
  141. data/test/jndi_callbacks_test.rb +40 -0
  142. data/test/jndi_test.rb +25 -0
  143. data/test/manualTestDatabase.rb +191 -0
  144. data/test/models/add_not_null_column_to_table.rb +12 -0
  145. data/test/models/auto_id.rb +18 -0
  146. data/test/models/data_types.rb +28 -0
  147. data/test/models/entry.rb +43 -0
  148. data/test/models/mixed_case.rb +25 -0
  149. data/test/models/reserved_word.rb +18 -0
  150. data/test/models/string_id.rb +18 -0
  151. data/test/models/validates_uniqueness_of_string.rb +19 -0
  152. data/test/mssql_db_create_test.rb +26 -0
  153. data/test/mssql_identity_insert_test.rb +19 -0
  154. data/test/mssql_legacy_types_test.rb +58 -0
  155. data/test/mssql_limit_offset_test.rb +136 -0
  156. data/test/mssql_multibyte_test.rb +18 -0
  157. data/test/mssql_simple_test.rb +55 -0
  158. data/test/mysql_db_create_test.rb +27 -0
  159. data/test/mysql_info_test.rb +123 -0
  160. data/test/mysql_multibyte_test.rb +10 -0
  161. data/test/mysql_nonstandard_primary_key_test.rb +42 -0
  162. data/test/mysql_simple_test.rb +49 -0
  163. data/test/oracle_simple_test.rb +18 -0
  164. data/test/oracle_specific_test.rb +83 -0
  165. data/test/pick_rails_version.rb +3 -0
  166. data/test/postgres_db_create_test.rb +32 -0
  167. data/test/postgres_drop_db_test.rb +16 -0
  168. data/test/postgres_mixed_case_test.rb +29 -0
  169. data/test/postgres_nonseq_pkey_test.rb +38 -0
  170. data/test/postgres_reserved_test.rb +22 -0
  171. data/test/postgres_schema_search_path_test.rb +44 -0
  172. data/test/postgres_simple_test.rb +65 -0
  173. data/test/postgres_table_alias_length_test.rb +15 -0
  174. data/test/simple.rb +546 -0
  175. data/test/sqlite3_simple_test.rb +233 -0
  176. data/test/sybase_jtds_simple_test.rb +28 -0
  177. metadata +259 -0
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'rake/testtask'
2
+ require 'rake/clean'
3
+ CLEAN.include 'derby*', 'test.db.*','test/reports', 'test.sqlite3','lib/**/*.jar','manifest.mf', '*.log'
4
+
5
+ task :default => [:java_compile, :test]
6
+
7
+ task :filelist do
8
+ puts FileList['pkg/**/*'].inspect
9
+ end
10
+
@@ -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 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,21 @@
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_Arel_Nodes_SelectCore x }.join,
9
+ ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
10
+ ("FETCH FIRST #{limit_for(o.limit)} ROWS ONLY" if o.limit),
11
+ (visit(o.offset) if o.offset),
12
+ (visit(o.lock) if o.lock),
13
+ ].compact.join ' '
14
+ end
15
+
16
+ def visit_Arel_Nodes_Offset o
17
+ "OFFSET #{visit o.value} ROWS"
18
+ end
19
+ end
20
+ end
21
+ 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
+
8
+ def select_count? o
9
+ sel = o.cores.length == 1 && o.cores.first
10
+ projections = sel.projections.length == 1 && sel.projections
11
+ Arel::Nodes::Count === projections.first
12
+ end
13
+
14
+ # Need to mimic the subquery logic in ARel 1.x for select count with limit
15
+ # See arel/engines/sql/compilers/mssql_compiler.rb for details
16
+ def visit_Arel_Nodes_SelectStatement o
17
+ order = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
18
+ if o.limit
19
+ if select_count?(o)
20
+ subquery = true
21
+ sql = o.cores.map do |x|
22
+ x = x.dup
23
+ x.projections = [Arel::Nodes::SqlLiteral.new("*")]
24
+ visit_Arel_Nodes_SelectCore x
25
+ end.join
26
+ else
27
+ sql = o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join
28
+ end
29
+
30
+ order ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
31
+ replace_limit_offset!(sql, limit_for(o.limit).to_i, o.offset && o.offset.value.to_i, order)
32
+ sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if subquery
33
+ elsif order
34
+ sql << " #{order}"
35
+ else
36
+ sql = super
37
+ end
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,29 @@
1
+ if defined?(JRUBY_VERSION)
2
+ begin
3
+ tried_gem ||= false
4
+ require 'active_record/version'
5
+ rescue LoadError
6
+ raise if tried_gem
7
+ require 'rubygems'
8
+ gem 'activerecord'
9
+ tried_gem = true
10
+ retry
11
+ end
12
+ if ActiveRecord::VERSION::MAJOR < 2
13
+ if defined?(RAILS_CONNECTION_ADAPTERS)
14
+ RAILS_CONNECTION_ADAPTERS << %q(jdbc)
15
+ else
16
+ RAILS_CONNECTION_ADAPTERS = %w(jdbc)
17
+ end
18
+ if ActiveRecord::VERSION::MAJOR == 1 && ActiveRecord::VERSION::MINOR == 14
19
+ require 'arjdbc/jdbc'
20
+ end
21
+ else
22
+ require 'active_record'
23
+ require 'arjdbc/jdbc'
24
+ end
25
+ else
26
+ warn "activerecord-jdbc-adapter is for use with JRuby only"
27
+ end
28
+
29
+ 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,413 @@
1
+ module ArJdbc
2
+ module DB2
3
+ def self.column_selector
4
+ [ /(db2|as400)/i,
5
+ lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
6
+ end
7
+
8
+ module Column
9
+ def type_cast(value)
10
+ return nil if value.nil? || value =~ /^\s*null\s*$/i
11
+ case type
12
+ when :string then value
13
+ when :integer then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
14
+ when :primary_key then defined?(value.to_i) ? value.to_i : (value ? 1 : 0)
15
+ when :float then value.to_f
16
+ when :datetime then ArJdbc::DB2::Column.cast_to_date_or_time(value)
17
+ when :date then ArJdbc::DB2::Column.cast_to_date_or_time(value)
18
+ when :timestamp then ArJdbc::DB2::Column.cast_to_time(value)
19
+ when :time then ArJdbc::DB2::Column.cast_to_time(value)
20
+ # TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def type_cast_code(var_name)
27
+ case type
28
+ when :datetime then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
29
+ when :date then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
30
+ when :timestamp then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
31
+ when :time then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+ def self.cast_to_date_or_time(value)
38
+ return value if value.is_a? Date
39
+ return nil if value.blank?
40
+ guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
41
+ end
42
+
43
+ def self.cast_to_time(value)
44
+ return value if value.is_a? Time
45
+ # AS400 returns a 2 digit year, LUW returns a 4 digit year, so comp = true to help out AS400
46
+ time_array = ParseDate.parsedate(value, true)
47
+ time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
48
+ Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
49
+ end
50
+
51
+ def self.guess_date_or_time(value)
52
+ (value.hour == 0 and value.min == 0 and value.sec == 0) ?
53
+ Date.new(value.year, value.month, value.day) : value
54
+ end
55
+
56
+ private
57
+ # <b>DEPRECATED:</b> SMALLINT is now used for boolean field types. Please
58
+ # convert your tables using DECIMAL(5) for boolean values to SMALLINT instead.
59
+ def use_decimal5_for_boolean
60
+ warn "[DEPRECATION] using DECIMAL(5) for boolean is deprecated. Convert your columns to SMALLINT instead."
61
+ :boolean
62
+ end
63
+
64
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
65
+ def simplified_type(field_type)
66
+ case field_type
67
+ # old jdbc_db2.rb used decimal(5,0) as boolean
68
+ when /^smallint/i then :boolean
69
+ when /^decimal\(5\)$/i then use_decimal5_for_boolean
70
+ when /^real/i then :float
71
+ when /^timestamp/i then :datetime
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+ # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
78
+ def default_value(value)
79
+ # IBM i (AS400) will return an empty string instead of null for no default
80
+ return nil if value.blank?
81
+
82
+ # string defaults are surrounded by single quotes
83
+ return $1 if value =~ /^'(.*)'$/
84
+
85
+ value
86
+ end
87
+ end
88
+
89
+ def _execute(sql, name = nil)
90
+ if ActiveRecord::ConnectionAdapters::JdbcConnection::select?(sql)
91
+ @connection.execute_query(sql)
92
+ elsif ActiveRecord::ConnectionAdapters::JdbcConnection::insert?(sql)
93
+ (@connection.execute_insert(sql) or last_insert_id(sql)).to_i
94
+ else
95
+ @connection.execute_update(sql)
96
+ end
97
+ end
98
+
99
+ # holy moly batman! all this to tell AS400 "yes i am sure"
100
+ def execute_and_auto_confirm(sql)
101
+ begin
102
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*SYSRPYL)',0000000031.00000)"
103
+ @connection.execute_update "call qsys.qcmdexc('ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY(''I'')',0000000045.00000)"
104
+ rescue Exception => e
105
+ raise "Could not call CHGJOB INQMSGRPY(*SYSRPYL) and ADDRPYLE SEQNBR(9876) MSGID(CPA32B2) RPY('I').\n" +
106
+ "Do you have authority to do this?\n\n" + e.to_s
107
+ end
108
+
109
+ r = execute sql
110
+
111
+ begin
112
+ @connection.execute_update "call qsys.qcmdexc('QSYS/CHGJOB INQMSGRPY(*DFT)',0000000027.00000)"
113
+ @connection.execute_update "call qsys.qcmdexc('RMVRPYLE SEQNBR(9876)',0000000021.00000)"
114
+ rescue Exception => e
115
+ raise "Could not call CHGJOB INQMSGRPY(*DFT) and RMVRPYLE SEQNBR(9876).\n" +
116
+ "Do you have authority to do this?\n\n" + e.to_s
117
+ end
118
+ r
119
+ end
120
+
121
+ def last_insert_id(sql)
122
+ table_name = sql.split(/\s/)[2]
123
+ result = select(ActiveRecord::Base.send(:sanitize_sql,
124
+ %[select IDENTITY_VAL_LOCAL() as last_insert_id from #{table_name}],
125
+ nil))
126
+ result.last['last_insert_id']
127
+ end
128
+
129
+ def modify_types(tp)
130
+ tp[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
131
+ tp[:string][:limit] = 255
132
+ tp[:integer][:limit] = nil
133
+ tp[:boolean] = {:name => "smallint"}
134
+ tp
135
+ end
136
+
137
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
138
+ limit = nil if type.to_sym == :integer
139
+ super(type, limit, precision, scale)
140
+ end
141
+
142
+ def adapter_name
143
+ 'DB2'
144
+ end
145
+
146
+ def arel2_visitors
147
+ require 'arel/visitors/db2'
148
+ {'db2' => ::Arel::Visitors::DB2, 'as400' => ::Arel::Visitors::DB2}
149
+ end
150
+
151
+ def add_limit_offset!(sql, options)
152
+ replace_limit_offset!(sql, options[:limit], options[:offset])
153
+ end
154
+
155
+ def replace_limit_offset!(sql, limit, offset)
156
+ if limit
157
+ limit = limit.to_i
158
+ if !offset
159
+ if limit == 1
160
+ sql << " FETCH FIRST ROW ONLY"
161
+ else
162
+ sql << " FETCH FIRST #{limit} ROWS ONLY"
163
+ end
164
+ else
165
+ offset = offset.to_i
166
+ sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
167
+ sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
168
+ end
169
+ end
170
+ sql
171
+ end
172
+
173
+ def pk_and_sequence_for(table)
174
+ # In JDBC/DB2 side, only upcase names of table and column are handled.
175
+ keys = super(table.upcase)
176
+ if keys && keys[0]
177
+ # In ActiveRecord side, only downcase names of table and column are handled.
178
+ keys[0] = keys[0].downcase
179
+ end
180
+ keys
181
+ end
182
+
183
+ def quote_column_name(column_name)
184
+ column_name
185
+ end
186
+
187
+ def quote(value, column = nil) # :nodoc:
188
+ if column && column.respond_to?(:primary) && column.primary && column.klass != String
189
+ return value.to_i.to_s
190
+ end
191
+ if column && (column.type == :decimal || column.type == :integer) && value
192
+ return value.to_s
193
+ end
194
+ case value
195
+ when String
196
+ if column && column.type == :binary
197
+ "BLOB('#{quote_string(value)}')"
198
+ else
199
+ "'#{quote_string(value)}'"
200
+ end
201
+ else super
202
+ end
203
+ end
204
+
205
+ def quote_string(string)
206
+ string.gsub(/'/, "''") # ' (for ruby-mode)
207
+ end
208
+
209
+ def quoted_true
210
+ '1'
211
+ end
212
+
213
+ def quoted_false
214
+ '0'
215
+ end
216
+
217
+ def reorg_table(table_name)
218
+ unless as400?
219
+ @connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
220
+ end
221
+ end
222
+
223
+ def recreate_database(name)
224
+ tables.each {|table| drop_table("#{db2_schema}.#{table}")}
225
+ end
226
+
227
+ def remove_index(table_name, options = { })
228
+ execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
229
+ end
230
+
231
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
232
+ # ...not supported on IBM i, so we raise in this case
233
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
234
+ if as400?
235
+ raise NotImplementedError, "rename_column is not supported on IBM i"
236
+ else
237
+ execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
238
+ reorg_table(table_name)
239
+ end
240
+ end
241
+
242
+ def change_column_null(table_name, column_name, null)
243
+ if null
244
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
245
+ else
246
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
247
+ end
248
+ reorg_table(table_name)
249
+ end
250
+
251
+ def change_column_default(table_name, column_name, default)
252
+ if default.nil?
253
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
254
+ else
255
+ execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
256
+ end
257
+ reorg_table(table_name)
258
+ end
259
+
260
+ def change_column(table_name, column_name, type, options = {})
261
+ data_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
262
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
263
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
264
+ reorg_table(table_name)
265
+
266
+ if options.include?(:default) and options.include?(:null)
267
+ # which to run first?
268
+ if options[:null] or options[:default].nil?
269
+ change_column_null(table_name, column_name, options[:null])
270
+ change_column_default(table_name, column_name, options[:default])
271
+ else
272
+ change_column_default(table_name, column_name, options[:default])
273
+ change_column_null(table_name, column_name, options[:null])
274
+ end
275
+ elsif options.include?(:default)
276
+ change_column_default(table_name, column_name, options[:default])
277
+ elsif options.include?(:null)
278
+ change_column_null(table_name, column_name, options[:null])
279
+ end
280
+ end
281
+
282
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
283
+ def remove_column(table_name, column_name) #:nodoc:
284
+ sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
285
+
286
+ as400? ? execute_and_auto_confirm(sql) : execute(sql)
287
+ reorg_table(table_name)
288
+ end
289
+
290
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
291
+ def rename_table(name, new_name) #:nodoc:
292
+ execute "RENAME TABLE #{name} TO #{new_name}"
293
+ reorg_table(new_name)
294
+ end
295
+
296
+ def tables
297
+ @connection.tables(nil, db2_schema, nil, ["TABLE"])
298
+ end
299
+
300
+ # only record precision and scale for types that can set
301
+ # them via CREATE TABLE:
302
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
303
+ HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
304
+ HAVE_PRECISION = %w(DECIMAL NUMERIC)
305
+ HAVE_SCALE = %w(DECIMAL NUMERIC)
306
+
307
+ def columns(table_name, name = nil)
308
+ cols = @connection.columns(table_name, name, db2_schema)
309
+
310
+ # scrub out sizing info when CREATE TABLE doesn't support it
311
+ # but JDBC reports it (doh!)
312
+ for col in cols
313
+ base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
314
+ col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
315
+ col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
316
+ #col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
317
+ end
318
+
319
+ cols
320
+ end
321
+
322
+ def indexes(table_name, name = nil)
323
+ @connection.indexes(table_name, name, db2_schema)
324
+ end
325
+
326
+ def add_quotes(name)
327
+ return name unless name
328
+ %Q{"#{name}"}
329
+ end
330
+
331
+ def strip_quotes(str)
332
+ return str unless str
333
+ return str unless /^(["']).*\1$/ =~ str
334
+ str[1..-2]
335
+ end
336
+
337
+ def expand_double_quotes(name)
338
+ return name unless name && name['"']
339
+ name.gsub(/"/,'""')
340
+ end
341
+
342
+ def structure_dump #:nodoc:
343
+ definition=""
344
+ rs = @connection.connection.meta_data.getTables(nil,db2_schema.upcase,nil,["TABLE"].to_java(:string))
345
+ while rs.next
346
+ tname = rs.getString(3)
347
+ definition << "CREATE TABLE #{tname} (\n"
348
+ rs2 = @connection.connection.meta_data.getColumns(nil,db2_schema.upcase,tname,nil)
349
+ first_col = true
350
+ while rs2.next
351
+ col_name = add_quotes(rs2.getString(4));
352
+ default = ""
353
+ d1 = rs2.getString(13)
354
+ # IBM i (as400 toolbox driver) will return an empty string if there is no default
355
+ if @config[:url] =~ /^jdbc:as400:/
356
+ default = !d1.blank? ? " DEFAULT #{d1}" : ""
357
+ else
358
+ default = d1 ? " DEFAULT #{d1}" : ""
359
+ end
360
+
361
+ type = rs2.getString(6)
362
+ col_precision = rs2.getString(7)
363
+ col_scale = rs2.getString(9)
364
+ col_size = ""
365
+ if HAVE_SCALE.include?(type) and col_scale
366
+ col_size = "(#{col_precision},#{col_scale})"
367
+ elsif (HAVE_LIMIT + HAVE_PRECISION).include?(type) and col_precision
368
+ col_size = "(#{col_precision})"
369
+ end
370
+ nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
371
+ create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
372
+ " " +
373
+ type +
374
+ col_size +
375
+ "" +
376
+ nulling +
377
+ default
378
+ if !first_col
379
+ create_col_string = ",\n #{create_col_string}"
380
+ else
381
+ create_col_string = " #{create_col_string}"
382
+ end
383
+
384
+ definition << create_col_string
385
+
386
+ first_col = false
387
+ end
388
+ definition << ");\n\n"
389
+ end
390
+ definition
391
+ end
392
+
393
+ private
394
+ def as400?
395
+ @config[:url] =~ /^jdbc:as400:/
396
+ end
397
+
398
+ def db2_schema
399
+ if @config[:schema].blank?
400
+ if as400?
401
+ # AS400 implementation takes schema from library name (last part of url)
402
+ schema = @config[:url].split('/').last.strip
403
+ (schema[-1..-1] == ";") ? schema.chop : schema
404
+ else
405
+ # LUW implementation uses schema name of username by default
406
+ @config[:username] or ENV['USER']
407
+ end
408
+ else
409
+ @config[:schema]
410
+ end
411
+ end
412
+ end
413
+ end