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