activerecord-jdbc-adapter 1.0.3-java → 50.1-java

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 (268) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +79 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +91 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +22 -17
  9. data/README.md +169 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +294 -5
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  15. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  16. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  19. data/lib/activerecord-jdbc-adapter.rb +0 -5
  20. data/lib/arel/visitors/compat.rb +60 -0
  21. data/lib/arel/visitors/db2.rb +128 -6
  22. data/lib/arel/visitors/derby.rb +103 -10
  23. data/lib/arel/visitors/firebird.rb +79 -0
  24. data/lib/arel/visitors/h2.rb +25 -0
  25. data/lib/arel/visitors/hsqldb.rb +18 -10
  26. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  27. data/lib/arel/visitors/sql_server.rb +225 -0
  28. data/lib/arel/visitors/sql_server/ng42.rb +293 -0
  29. data/lib/arjdbc.rb +11 -21
  30. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  31. data/lib/arjdbc/abstract/core.rb +64 -0
  32. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  33. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  34. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  35. data/lib/arjdbc/db2.rb +3 -1
  36. data/lib/arjdbc/db2/adapter.rb +630 -250
  37. data/lib/arjdbc/db2/as400.rb +130 -0
  38. data/lib/arjdbc/db2/column.rb +167 -0
  39. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  40. data/lib/arjdbc/derby.rb +1 -5
  41. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  42. data/lib/arjdbc/derby/adapter.rb +409 -217
  43. data/lib/arjdbc/derby/connection_methods.rb +16 -14
  44. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  45. data/lib/arjdbc/discover.rb +62 -50
  46. data/lib/arjdbc/firebird.rb +3 -1
  47. data/lib/arjdbc/firebird/adapter.rb +365 -62
  48. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  49. data/lib/arjdbc/h2.rb +2 -3
  50. data/lib/arjdbc/h2/adapter.rb +273 -6
  51. data/lib/arjdbc/h2/connection_methods.rb +23 -8
  52. data/lib/arjdbc/hsqldb.rb +2 -3
  53. data/lib/arjdbc/hsqldb/adapter.rb +204 -77
  54. data/lib/arjdbc/hsqldb/connection_methods.rb +24 -10
  55. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  56. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  57. data/lib/arjdbc/informix.rb +4 -2
  58. data/lib/arjdbc/informix/adapter.rb +78 -54
  59. data/lib/arjdbc/informix/connection_methods.rb +8 -9
  60. data/lib/arjdbc/jdbc.rb +59 -2
  61. data/lib/arjdbc/jdbc/adapter.rb +356 -166
  62. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  63. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  64. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  65. data/lib/arjdbc/jdbc/callbacks.rb +27 -18
  66. data/lib/arjdbc/jdbc/column.rb +79 -20
  67. data/lib/arjdbc/jdbc/connection.rb +5 -119
  68. data/lib/arjdbc/jdbc/connection_methods.rb +32 -4
  69. data/lib/arjdbc/jdbc/error.rb +65 -0
  70. data/lib/arjdbc/jdbc/extension.rb +41 -29
  71. data/lib/arjdbc/jdbc/java.rb +5 -6
  72. data/lib/arjdbc/jdbc/jdbc.rake +3 -126
  73. data/lib/arjdbc/jdbc/railtie.rb +2 -9
  74. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
  75. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  76. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  77. data/lib/arjdbc/jdbc/type_converter.rb +35 -19
  78. data/lib/arjdbc/mssql.rb +6 -3
  79. data/lib/arjdbc/mssql/adapter.rb +630 -298
  80. data/lib/arjdbc/mssql/column.rb +200 -0
  81. data/lib/arjdbc/mssql/connection_methods.rb +66 -17
  82. data/lib/arjdbc/mssql/explain_support.rb +99 -0
  83. data/lib/arjdbc/mssql/limit_helpers.rb +189 -50
  84. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  85. data/lib/arjdbc/mssql/types.rb +343 -0
  86. data/lib/arjdbc/mssql/utils.rb +82 -0
  87. data/lib/arjdbc/mysql.rb +2 -3
  88. data/lib/arjdbc/mysql/adapter.rb +86 -356
  89. data/lib/arjdbc/mysql/connection_methods.rb +159 -23
  90. data/lib/arjdbc/oracle/adapter.rb +714 -263
  91. data/lib/arjdbc/postgresql.rb +2 -3
  92. data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +24 -0
  93. data/lib/arjdbc/postgresql/adapter.rb +570 -400
  94. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  95. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  96. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  97. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  98. data/lib/arjdbc/postgresql/column.rb +51 -0
  99. data/lib/arjdbc/postgresql/connection_methods.rb +57 -18
  100. data/lib/arjdbc/postgresql/name.rb +24 -0
  101. data/lib/arjdbc/postgresql/oid_types.rb +192 -0
  102. data/lib/arjdbc/railtie.rb +11 -0
  103. data/lib/arjdbc/sqlite3.rb +2 -3
  104. data/lib/arjdbc/sqlite3/adapter.rb +518 -198
  105. data/lib/arjdbc/sqlite3/connection_methods.rb +49 -24
  106. data/lib/arjdbc/sybase.rb +2 -2
  107. data/lib/arjdbc/sybase/adapter.rb +7 -6
  108. data/lib/arjdbc/tasks.rb +13 -0
  109. data/lib/arjdbc/tasks/database_tasks.rb +52 -0
  110. data/lib/arjdbc/tasks/databases.rake +91 -0
  111. data/lib/arjdbc/tasks/databases3.rake +215 -0
  112. data/lib/arjdbc/tasks/databases4.rake +39 -0
  113. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  114. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  115. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  116. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  117. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  118. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  119. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  120. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  121. data/lib/arjdbc/util/table_copier.rb +110 -0
  122. data/lib/arjdbc/version.rb +1 -6
  123. data/lib/generators/jdbc/USAGE +9 -0
  124. data/lib/generators/jdbc/jdbc_generator.rb +8 -0
  125. data/lib/jdbc_adapter.rb +1 -1
  126. data/lib/jdbc_adapter/rake_tasks.rb +3 -2
  127. data/lib/jdbc_adapter/version.rb +2 -1
  128. data/pom.xml +114 -0
  129. data/rails_generators/jdbc_generator.rb +1 -1
  130. data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
  131. data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
  132. data/rakelib/01-tomcat.rake +51 -0
  133. data/rakelib/02-test.rake +132 -0
  134. data/rakelib/bundler_ext.rb +11 -0
  135. data/rakelib/compile.rake +67 -22
  136. data/rakelib/db.rake +61 -0
  137. data/rakelib/rails.rake +204 -29
  138. data/src/java/arjdbc/ArJdbcModule.java +286 -0
  139. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  140. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  141. data/src/java/arjdbc/derby/DerbyModule.java +99 -243
  142. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  143. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  144. data/src/java/arjdbc/{jdbc/JdbcConnectionFactory.java → h2/H2Module.java} +20 -6
  145. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +27 -12
  146. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  147. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  148. data/src/java/arjdbc/jdbc/AdapterJavaService.java +7 -29
  149. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  150. data/src/java/arjdbc/jdbc/ConnectionFactory.java +132 -0
  151. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +157 -0
  152. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  153. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  154. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  155. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3622 -948
  156. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  157. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +181 -0
  158. data/src/java/arjdbc/mysql/MySQLModule.java +99 -81
  159. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  160. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  161. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +387 -17
  162. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  163. data/src/java/arjdbc/postgresql/PgResultSetMetaDataWrapper.java +23 -0
  164. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  165. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +184 -0
  166. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +952 -0
  167. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  168. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  169. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  170. data/src/java/arjdbc/util/DateTimeUtils.java +580 -0
  171. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  172. data/src/java/arjdbc/util/QuotingUtils.java +138 -0
  173. data/src/java/arjdbc/util/StringCache.java +63 -0
  174. data/src/java/arjdbc/util/StringHelper.java +159 -0
  175. metadata +245 -268
  176. data/History.txt +0 -369
  177. data/Manifest.txt +0 -180
  178. data/README.txt +0 -181
  179. data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
  180. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  181. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  182. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  183. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  184. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  185. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  186. data/lib/arel/visitors/mssql.rb +0 -44
  187. data/lib/arjdbc/jdbc/compatibility.rb +0 -51
  188. data/lib/arjdbc/jdbc/core_ext.rb +0 -24
  189. data/lib/arjdbc/jdbc/discover.rb +0 -18
  190. data/lib/arjdbc/jdbc/driver.rb +0 -44
  191. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -87
  192. data/lib/arjdbc/jdbc/quoted_primary_key.rb +0 -28
  193. data/lib/arjdbc/jdbc/require_driver.rb +0 -16
  194. data/lib/arjdbc/mimer.rb +0 -2
  195. data/lib/arjdbc/mimer/adapter.rb +0 -142
  196. data/lib/arjdbc/mssql/tsql_helper.rb +0 -61
  197. data/lib/arjdbc/oracle.rb +0 -3
  198. data/lib/arjdbc/oracle/connection_methods.rb +0 -11
  199. data/lib/pg.rb +0 -4
  200. data/rakelib/package.rake +0 -92
  201. data/rakelib/test.rake +0 -81
  202. data/src/java/arjdbc/jdbc/SQLBlock.java +0 -48
  203. data/src/java/arjdbc/mssql/MssqlRubyJdbcConnection.java +0 -127
  204. data/src/java/arjdbc/postgresql/PostgresqlRubyJdbcConnection.java +0 -57
  205. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +0 -64
  206. data/test/abstract_db_create.rb +0 -117
  207. data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -31
  208. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  209. data/test/db/db2.rb +0 -11
  210. data/test/db/derby.rb +0 -12
  211. data/test/db/h2.rb +0 -11
  212. data/test/db/hsqldb.rb +0 -13
  213. data/test/db/informix.rb +0 -11
  214. data/test/db/jdbc.rb +0 -11
  215. data/test/db/jndi_config.rb +0 -40
  216. data/test/db/logger.rb +0 -3
  217. data/test/db/mssql.rb +0 -9
  218. data/test/db/mysql.rb +0 -10
  219. data/test/db/oracle.rb +0 -34
  220. data/test/db/postgres.rb +0 -9
  221. data/test/db/sqlite3.rb +0 -11
  222. data/test/db2_simple_test.rb +0 -66
  223. data/test/derby_migration_test.rb +0 -68
  224. data/test/derby_multibyte_test.rb +0 -12
  225. data/test/derby_simple_test.rb +0 -99
  226. data/test/generic_jdbc_connection_test.rb +0 -29
  227. data/test/h2_simple_test.rb +0 -41
  228. data/test/has_many_through.rb +0 -79
  229. data/test/helper.rb +0 -5
  230. data/test/hsqldb_simple_test.rb +0 -6
  231. data/test/informix_simple_test.rb +0 -48
  232. data/test/jdbc_common.rb +0 -25
  233. data/test/jndi_callbacks_test.rb +0 -40
  234. data/test/jndi_test.rb +0 -25
  235. data/test/manualTestDatabase.rb +0 -191
  236. data/test/models/add_not_null_column_to_table.rb +0 -12
  237. data/test/models/auto_id.rb +0 -18
  238. data/test/models/data_types.rb +0 -28
  239. data/test/models/entry.rb +0 -43
  240. data/test/models/mixed_case.rb +0 -25
  241. data/test/models/reserved_word.rb +0 -18
  242. data/test/models/string_id.rb +0 -18
  243. data/test/models/validates_uniqueness_of_string.rb +0 -19
  244. data/test/mssql_db_create_test.rb +0 -26
  245. data/test/mssql_identity_insert_test.rb +0 -19
  246. data/test/mssql_legacy_types_test.rb +0 -58
  247. data/test/mssql_limit_offset_test.rb +0 -136
  248. data/test/mssql_multibyte_test.rb +0 -18
  249. data/test/mssql_simple_test.rb +0 -55
  250. data/test/mysql_db_create_test.rb +0 -27
  251. data/test/mysql_info_test.rb +0 -113
  252. data/test/mysql_multibyte_test.rb +0 -10
  253. data/test/mysql_nonstandard_primary_key_test.rb +0 -42
  254. data/test/mysql_simple_test.rb +0 -49
  255. data/test/oracle_simple_test.rb +0 -18
  256. data/test/oracle_specific_test.rb +0 -83
  257. data/test/pick_rails_version.rb +0 -3
  258. data/test/postgres_db_create_test.rb +0 -32
  259. data/test/postgres_drop_db_test.rb +0 -16
  260. data/test/postgres_mixed_case_test.rb +0 -29
  261. data/test/postgres_nonseq_pkey_test.rb +0 -38
  262. data/test/postgres_reserved_test.rb +0 -22
  263. data/test/postgres_schema_search_path_test.rb +0 -44
  264. data/test/postgres_simple_test.rb +0 -51
  265. data/test/postgres_table_alias_length_test.rb +0 -15
  266. data/test/simple.rb +0 -546
  267. data/test/sqlite3_simple_test.rb +0 -233
  268. data/test/sybase_jtds_simple_test.rb +0 -28
@@ -1,29 +1,19 @@
1
1
  if defined?(JRUBY_VERSION)
2
2
  begin
3
- tried_gem ||= false
4
3
  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
4
  require 'active_record'
23
- require 'arjdbc/jdbc'
5
+ rescue LoadError => e
6
+ warn "activerecord-jdbc-adapter requires the activerecord gem at runtime"
7
+ raise e
24
8
  end
9
+ require 'arjdbc/jdbc'
10
+ begin
11
+ require 'arjdbc/railtie'
12
+ rescue LoadError => e
13
+ warn "activerecord-jdbc-adapter failed to load railtie: #{e.inspect}"
14
+ end if defined?(Rails) && ActiveRecord::VERSION::MAJOR >= 3
25
15
  else
26
- warn "ActiveRecord-JDBC is for use with JRuby only"
16
+ warn "activerecord-jdbc-adapter is for use with JRuby only"
27
17
  end
28
18
 
29
- require 'arjdbc/version'
19
+ require 'arjdbc/version'
@@ -0,0 +1,35 @@
1
+ module ArJdbc
2
+ module Abstract
3
+ module ConnectionManagement
4
+
5
+ # @override
6
+ def active?
7
+ return unless @connection
8
+ @connection.active?
9
+ end
10
+
11
+ # @override
12
+ def reconnect!
13
+ super # clear_cache! && reset_transaction
14
+ @connection.reconnect! # handles adapter.configure_connection
15
+ end
16
+
17
+ # @override
18
+ def disconnect!
19
+ super # clear_cache! && reset_transaction
20
+ return unless @connection
21
+ @connection.disconnect!
22
+ end
23
+
24
+ # @override
25
+ # def verify!(*ignored)
26
+ # if @connection && @connection.jndi?
27
+ # # checkout call-back does #reconnect!
28
+ # else
29
+ # reconnect! unless active? # super
30
+ # end
31
+ # end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,64 @@
1
+ module ArJdbc
2
+ module Abstract
3
+
4
+ # This is minimum amount of code needed from base JDBC Adapter class to make common adapters
5
+ # work. This replaces using jdbc/adapter as a base class for all adapters.
6
+ module Core
7
+
8
+ attr_reader :config
9
+
10
+ def initialize(connection, logger = nil, config = {})
11
+ @config = config
12
+
13
+ if self.class.equal? ActiveRecord::ConnectionAdapters::JdbcAdapter
14
+ spec = @config.key?(:adapter_spec) ? @config[:adapter_spec] :
15
+ ( @config[:adapter_spec] = adapter_spec(@config) ) # due resolving visitor
16
+ extend spec if spec
17
+ end
18
+
19
+ connection ||= jdbc_connection_class(config[:adapter_spec]).new(config, self)
20
+
21
+ super(connection, logger, config) # AbstractAdapter
22
+
23
+ connection.configure_connection # will call us (maybe)
24
+ end
25
+
26
+ # Retrieve the raw `java.sql.Connection` object.
27
+ # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
28
+ # connection should be made - to really return the 'native' JDBC object.
29
+ # @param unwrap [true, false] whether to unwrap the connection object
30
+ # @return [Java::JavaSql::Connection] the JDBC connection
31
+ def jdbc_connection(unwrap = nil)
32
+ raw_connection.jdbc_connection(unwrap)
33
+ end
34
+
35
+ protected
36
+
37
+ def translate_exception_class(e, sql)
38
+ begin
39
+ message = "#{e.class.name}: #{e.message}: #{sql}"
40
+ rescue Encoding::CompatibilityError
41
+ message = "#{e.class.name}: #{e.message.force_encoding sql.encoding}: #{sql}"
42
+ end
43
+
44
+ exception = translate_exception(e, message)
45
+ exception.set_backtrace e.backtrace unless e.equal?(exception)
46
+ exception
47
+ end
48
+
49
+ def translate_exception(e, message)
50
+ # we shall not translate native "Java" exceptions as they might
51
+ # swallow an ArJdbc / driver bug into an AR::StatementInvalid !
52
+ return e if e.is_a?(Java::JavaLang::Throwable)
53
+
54
+ case e
55
+ when SystemExit, SignalException, NoMemoryError then e
56
+ when ActiveModel::RangeError, TypeError, RuntimeError then e
57
+ else ActiveRecord::StatementInvalid.new(message)
58
+ end
59
+ end
60
+
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArJdbc
4
+ module Abstract
5
+
6
+ # This provides the basic interface for interacting with the
7
+ # database for JDBC based adapters
8
+ module DatabaseStatements
9
+
10
+ NO_BINDS = [].freeze
11
+
12
+ def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil)
13
+ if without_prepared_statement?(binds)
14
+ log(sql, name) { @connection.execute_insert(sql) }
15
+ else
16
+ log(sql, name, binds) do
17
+ @connection.execute_insert(sql, binds)
18
+ end
19
+ end
20
+ end
21
+
22
+ # It appears that at this point (AR 5.0) "prepare" should only ever be true
23
+ # if prepared statements are enabled
24
+ def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false)
25
+ if without_prepared_statement?(binds)
26
+ log(sql, name) { @connection.execute_query(sql) }
27
+ else
28
+ log(sql, name, binds) do
29
+ # It seems that #supports_statement_cache? is defined but isn't checked before setting "prepare" (AR 5.0)
30
+ cached_statement = fetch_cached_statement(sql) if prepare && supports_statement_cache?
31
+ @connection.execute_prepared_query(sql, binds, cached_statement)
32
+ end
33
+ end
34
+ end
35
+
36
+ def exec_update(sql, name = nil, binds = NO_BINDS)
37
+ if without_prepared_statement?(binds)
38
+ log(sql, name) { @connection.execute_update(sql) }
39
+ else
40
+ log(sql, name, binds) { @connection.execute_prepared_update(sql, binds) }
41
+ end
42
+ end
43
+ alias :exec_delete :exec_update
44
+
45
+ def execute(sql, name = nil)
46
+ log(sql, name) { @connection.execute(sql) }
47
+ end
48
+
49
+ def select_all(arel, name = nil, binds = NO_BINDS, preparable: nil)
50
+ binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
51
+ super
52
+ end
53
+
54
+ private
55
+
56
+ def convert_legacy_binds_to_attributes(binds)
57
+ binds.map do |column, value|
58
+ ActiveRecord::Relation::QueryAttribute.new(nil, type_cast(value, column), ActiveModel::Type::Value.new)
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_record/connection_adapters/statement_pool'
2
+
3
+ module ArJdbc
4
+ module Abstract
5
+ module StatementCache
6
+
7
+ # This works a little differently than the AR implementation in that
8
+ # we are storing an actual PreparedStatement object instead of just
9
+ # the name of the prepared statement
10
+ class StatementPool < ActiveRecord::ConnectionAdapters::StatementPool
11
+
12
+ private
13
+
14
+ def dealloc(statement)
15
+ statement.close
16
+ end
17
+
18
+ end
19
+
20
+ def initialize(*args) # (connection, logger, config)
21
+ super
22
+
23
+ # Only say we support the statement cache if we are using prepared statements
24
+ # and have a max number of statements defined
25
+ statement_limit = self.class.type_cast_config_to_integer(config[:statement_limit])
26
+ @jdbc_statement_cache_enabled = config[:prepared_statements] && (statement_limit.nil? || statement_limit > 0)
27
+
28
+ @statements = StatementPool.new(statement_limit) # AR (5.0) expects this to be stored as @statements
29
+ end
30
+
31
+ # Clears the prepared statements cache.
32
+ def clear_cache!
33
+ @statements.clear
34
+ end
35
+
36
+ def delete_cached_statement(sql)
37
+ @statements.delete(cached_statement_key(sql))
38
+ end
39
+
40
+ def fetch_cached_statement(sql)
41
+ @statements[cached_statement_key(sql)] ||= @connection.connection.prepare_statement(sql)
42
+ end
43
+
44
+ def supports_statement_cache?
45
+ @jdbc_statement_cache_enabled
46
+ end
47
+
48
+ private
49
+
50
+ # This should be overridden by the adapter if the sql itself
51
+ # is not enough to make the key unique
52
+ def cached_statement_key(sql)
53
+ sql
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,86 @@
1
+ module ArJdbc
2
+ module Abstract
3
+
4
+ # Provides the basic interface needed to support transactions for JDBC based adapters
5
+ module TransactionSupport
6
+
7
+ ########################## Support Checks #################################
8
+
9
+ # Does our database (+ its JDBC driver) support save-points?
10
+ # @since 1.3.0
11
+ # @override
12
+ def supports_savepoints?
13
+ @connection.supports_savepoints?
14
+ end
15
+
16
+ # Does this adapter support setting the isolation level for a transaction?
17
+ # Unlike 'plain' `ActiveRecord` we allow checking for concrete transaction
18
+ # isolation level support by the database.
19
+ # @param level optional to check if we support a specific isolation level
20
+ # @since 1.3.0
21
+ # @extension added optional level parameter
22
+ def supports_transaction_isolation?(level = nil)
23
+ return false unless level
24
+ @connection.supports_transaction_isolation?(level)
25
+ end
26
+
27
+ ########################## Transaction Interface ##########################
28
+
29
+ # Starts a database transaction.
30
+ # @override
31
+ def begin_db_transaction
32
+ log('BEGIN TRANSACTION'.freeze, nil) { @connection.begin }
33
+ end
34
+
35
+ # Starts a database transaction.
36
+ # @param isolation the transaction isolation to use
37
+ def begin_isolated_db_transaction(isolation)
38
+ log("BEGIN ISOLATED TRANSACTION - #{isolation}", nil) { @connection.begin(isolation) }
39
+ end
40
+
41
+ # Commits the current database transaction.
42
+ # @override
43
+ def commit_db_transaction
44
+ log('COMMIT TRANSACTION'.freeze, nil) { @connection.commit }
45
+ end
46
+
47
+ # Rolls back the current database transaction.
48
+ # Called from 'rollback_db_transaction' in the AbstractAdapter
49
+ # @override
50
+ def exec_rollback_db_transaction
51
+ log('ROLLBACK TRANSACTION'.freeze, nil) { @connection.rollback }
52
+ end
53
+
54
+ ########################## Savepoint Interface ############################
55
+
56
+ # Creates a (transactional) save-point one can rollback to.
57
+ # Unlike 'plain' `ActiveRecord` it is allowed to pass a save-point name.
58
+ # @param name the save-point name
59
+ # @return save-point name (even if nil passed will be generated)
60
+ # @since 1.3.0
61
+ # @extension added optional name parameter
62
+ def create_savepoint(name = current_savepoint_name)
63
+ log("SAVEPOINT #{name}", 'Savepoint') { @connection.create_savepoint(name) }
64
+ end
65
+
66
+ # Transaction rollback to a given (previously created) save-point.
67
+ # If no save-point name given rollback to the last created one.
68
+ # Called from 'rollback_to_savepoint' in AbstractAdapter
69
+ # @param name the save-point name
70
+ # @extension added optional name parameter
71
+ def exec_rollback_to_savepoint(name = current_savepoint_name)
72
+ log("ROLLBACK TO SAVEPOINT #{name}", 'Savepoint') { @connection.rollback_savepoint(name) }
73
+ end
74
+
75
+ # Release a previously created save-point.
76
+ # @note Save-points are auto-released with the transaction they're created
77
+ # in (on transaction commit or roll-back).
78
+ # @param name the save-point name
79
+ # @extension added optional name parameter
80
+ def release_savepoint(name = current_savepoint_name)
81
+ log("RELEASE SAVEPOINT #{name}", 'Savepoint') { @connection.release_savepoint(name) }
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -1,2 +1,4 @@
1
- require 'arjdbc/jdbc'
1
+ require 'arjdbc'
2
2
  require 'arjdbc/db2/adapter'
3
+ require 'arjdbc/db2/connection_methods'
4
+ ArJdbc.warn_unsupported_adapter 'db2', [4, 2] # warns on AR >= 4.2
@@ -1,170 +1,334 @@
1
+ # NOTE: file contains code adapted from **ruby-ibmdb** adapter, license follows
2
+ =begin
3
+ Copyright (c) 2006 - 2015 IBM Corporation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ =end
24
+
25
+ ArJdbc.load_java_part :DB2
26
+
27
+ require 'arjdbc/db2/column'
28
+
1
29
  module ArJdbc
30
+ # @note This adapter doesn't support explain `config.active_record.auto_explain_threshold_in_seconds` should be commented (Rails < 4.0)
2
31
  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
32
+
33
+ # @private
34
+ def self.extended(adapter); initialize!; end
35
+
36
+ # @private
37
+ @@_initialized = nil
38
+
39
+ # @private
40
+ def self.initialize!
41
+ return if @@_initialized; @@_initialized = true
42
+
43
+ require 'arjdbc/util/serialized_attributes'
44
+ Util::SerializedAttributes.setup /blob|clob/i, 'after_save_with_db2_lob'
45
+ end
46
+
47
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
48
+ def self.jdbc_connection_class
49
+ ::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
50
+ end
51
+
52
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
53
+ def jdbc_column_class
54
+ ::ActiveRecord::ConnectionAdapters::DB2Column
55
+ end
56
+
57
+ # @private
58
+ @@emulate_booleans = true
59
+
60
+ # Boolean emulation can be disabled using :
61
+ #
62
+ # ArJdbc::DB2.emulate_booleans = false
63
+ #
64
+ def self.emulate_booleans?; @@emulate_booleans; end
65
+ # @deprecated Use {#emulate_booleans?} instead.
66
+ def self.emulate_booleans; @@emulate_booleans; end
67
+ # @see #emulate_booleans?
68
+ def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
69
+
70
+ # @private
71
+ @@update_lob_values = true
72
+
73
+ # Updating records with LOB values (binary/text columns) in a separate
74
+ # statement can be disabled using :
75
+ #
76
+ # ArJdbc::DB2.update_lob_values = false
77
+ #
78
+ # @note This only applies when prepared statements are not used.
79
+ def self.update_lob_values?; @@update_lob_values; end
80
+ # @see #update_lob_values?
81
+ def self.update_lob_values=(update); @@update_lob_values = update; end
82
+
83
+ # @see #update_lob_values?
84
+ # @see ArJdbc::Util::SerializedAttributes#update_lob_columns
85
+ def update_lob_value?(value, column = nil)
86
+ DB2.update_lob_values? && ! prepared_statements? # && value
87
+ end
88
+
89
+ # @see #quote
90
+ # @private
91
+ BLOB_VALUE_MARKER = "BLOB('')"
92
+ # @see #quote
93
+ # @private
94
+ CLOB_VALUE_MARKER = "''"
95
+
96
+ def configure_connection
97
+ schema = self.schema
98
+ set_schema(schema) if schema && schema != config[:username]
99
+ end
100
+
101
+ ADAPTER_NAME = 'DB2'.freeze
102
+
103
+ def adapter_name
104
+ ADAPTER_NAME
105
+ end
106
+
107
+ NATIVE_DATABASE_TYPES = {
108
+ :string => { :name => "varchar", :limit => 255 },
109
+ :integer => { :name => "integer" },
110
+ :bigint => { :name => 'bigint' },
111
+ :float => { :name => "real" }, # :limit => 24
112
+ :double => { :name => "double" }, # :limit => 53
113
+ :text => { :name => "clob" },
114
+ :binary => { :name => "blob" },
115
+ :xml => { :name => "xml" },
116
+ :decimal => { :name => "decimal" }, # :limit => 31
117
+ :char => { :name => "char" }, # :limit => 254
118
+ :date => { :name => "date" },
119
+ :datetime => { :name => "timestamp" },
120
+ :timestamp => { :name => "timestamp" },
121
+ :time => { :name => "time" },
122
+ :boolean => { :name => "smallint" }, # no native boolean type
123
+ #:rowid => { :name => "rowid" }, # rowid is a supported datatype on z/OS and i/5
124
+ #:serial => { :name => "serial" }, # supported datatype on Informix Dynamic Server
125
+ #:graphic => { :name => "graphic", :limit => 1 }, # :limit => 127
126
+ }
127
+
128
+ # @override
129
+ def initialize_type_map(m)
130
+ register_class_with_limit m, %r(boolean)i, ActiveRecord::Type::Boolean
131
+ register_class_with_limit m, %r(char)i, ActiveRecord::Type::String
132
+ register_class_with_limit m, %r(binary)i, ActiveRecord::Type::Binary
133
+ register_class_with_limit m, %r(text)i, ActiveRecord::Type::Text
134
+ register_class_with_limit m, %r(date)i, ActiveRecord::Type::Date
135
+ register_class_with_limit m, %r(time)i, ActiveRecord::Type::Time
136
+ register_class_with_limit m, %r(datetime)i, ActiveRecord::Type::DateTime
137
+ register_class_with_limit m, %r(float)i, ActiveRecord::Type::Float
138
+ register_class_with_limit m, %r(int)i, ActiveRecord::Type::Integer
139
+
140
+ m.alias_type %r(blob)i, 'binary'
141
+ m.alias_type %r(clob)i, 'text'
142
+ m.alias_type %r(timestamp)i, 'datetime'
143
+ m.alias_type %r(numeric)i, 'decimal'
144
+ m.alias_type %r(number)i, 'decimal'
145
+ m.alias_type %r(double)i, 'float'
146
+ m.alias_type %r(real)i, 'float'
147
+
148
+ m.register_type(%r(decimal)i) do |sql_type|
149
+ scale = extract_scale(sql_type)
150
+ precision = extract_precision(sql_type)
151
+ limit = extract_limit(sql_type)
152
+ if scale == 0
153
+ ActiveRecord::Type::BigInteger.new(:precision => precision, :limit => limit)
21
154
  else
22
- super
155
+ ActiveRecord::Type::Decimal.new(:precision => precision, :scale => scale)
23
156
  end
24
157
  end
25
158
 
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})"
159
+ m.alias_type %r(for bit data)i, 'binary'
160
+ m.alias_type %r(smallint)i, 'boolean'
161
+ m.alias_type %r(serial)i, 'int'
162
+ m.alias_type %r(decfloat)i, 'decimal'
163
+ #m.alias_type %r(real)i, 'decimal'
164
+ m.alias_type %r(graphic)i, 'binary'
165
+ m.alias_type %r(rowid)i, 'int'
166
+
167
+ m.register_type(%r(smallint)i) do
168
+ if DB2.emulate_booleans?
169
+ ActiveRecord::Type::Boolean.new
32
170
  else
33
- super
171
+ ActiveRecord::Type::Integer.new(:limit => 1)
34
172
  end
35
173
  end
36
174
 
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
175
+ m.register_type %r(xml)i, XmlType.new
176
+ end if AR42
42
177
 
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
178
+ # @private
179
+ class XmlType < ActiveRecord::Type::String
180
+ def type; :xml end
50
181
 
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
182
+ def type_cast_for_database(value)
183
+ return unless value
184
+ Data.new(super)
54
185
  end
55
186
 
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
187
+ class Data
188
+ def initialize(value)
189
+ @value = value
190
+ end
191
+ def to_s; @value end
62
192
  end
193
+ end if AR42
63
194
 
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
195
+ # @override
196
+ def reset_column_information
197
+ initialize_type_map(type_map)
198
+ end if AR42
199
+
200
+ # @override
201
+ def native_database_types
202
+ # NOTE: currently merging with what JDBC gives us since there's a lot
203
+ # of DB2-like stuff we could be connecting e.g. "classic", Z/OS etc.
204
+ # types = super
205
+ types = super.merge(NATIVE_DATABASE_TYPES)
206
+ types
207
+ end
208
+
209
+ # @private
210
+ class TableDefinition < ::ActiveRecord::ConnectionAdapters::TableDefinition
211
+
212
+ def xml(*args)
213
+ options = args.extract_options!
214
+ column(args[0], 'xml', options)
75
215
  end
76
216
 
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?
217
+ # IBM DB adapter (MRI) compatibility :
81
218
 
82
- # string defaults are surrounded by single quotes
83
- return $1 if value =~ /^'(.*)'$/
219
+ # @private
220
+ # @deprecated
221
+ def double(*args)
222
+ options = args.extract_options!
223
+ column(args[0], 'double', options)
224
+ end
84
225
 
85
- value
226
+ # @private
227
+ def decfloat(*args)
228
+ options = args.extract_options!
229
+ column(args[0], 'decfloat', options)
86
230
  end
87
- end
88
231
 
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)
232
+ def graphic(*args)
233
+ options = args.extract_options!
234
+ column(args[0], 'graphic', options)
96
235
  end
97
- end
98
236
 
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
237
+ # @private
238
+ # @deprecated
239
+ def vargraphic(*args)
240
+ options = args.extract_options!
241
+ column(args[0], 'vargraphic', options)
107
242
  end
108
243
 
109
- r = execute sql
244
+ # @private
245
+ # @deprecated
246
+ def bigint(*args)
247
+ options = args.extract_options!
248
+ column(args[0], 'bigint', options)
249
+ end
110
250
 
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
251
+ def char(*args)
252
+ options = args.extract_options!
253
+ column(args[0], 'char', options)
117
254
  end
118
- r
119
- end
255
+ # alias_method :character, :char
120
256
 
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
257
  end
128
258
 
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
259
+ def table_definition(*args)
260
+ new_table_definition(TableDefinition, *args)
135
261
  end
136
262
 
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)
263
+ def prefetch_primary_key?(table_name = nil)
264
+ # TRUE if the table has no identity column
265
+ names = table_name.upcase.split(".")
266
+ sql = "SELECT 1 FROM SYSCAT.COLUMNS WHERE IDENTITY = 'Y' "
267
+ sql << "AND TABSCHEMA = '#{names.first}' " if names.size == 2
268
+ sql << "AND TABNAME = '#{names.last}'"
269
+ select_one(sql).nil?
140
270
  end
141
271
 
142
- def adapter_name
143
- 'DB2'
272
+ def next_sequence_value(sequence_name)
273
+ select_value("SELECT NEXT VALUE FOR #{sequence_name} FROM sysibm.sysdummy1")
144
274
  end
145
275
 
146
- def arel2_visitors
147
- require 'arel/visitors/db2'
148
- {'db2' => ::Arel::Visitors::DB2, 'as400' => ::Arel::Visitors::DB2}
276
+ def create_table(name, options = {}, &block)
277
+ if zos?
278
+ zos_create_table(name, options, &block)
279
+ else
280
+ super
281
+ end
149
282
  end
150
283
 
151
- def add_limit_offset!(sql, options)
152
- replace_limit_offset!(sql, options[:limit], options[:offset])
153
- end
284
+ def zos_create_table(name, options = {})
285
+ table_definition = new_table_definition TableDefinition, name, options[:temporary], options[:options], options[:as]
154
286
 
155
- def replace_limit_offset!(sql, limit, offset)
156
- if limit && !offset
157
- if limit == 1
158
- sql << " FETCH FIRST ROW ONLY"
159
- else
160
- sql << " FETCH FIRST #{sanitize_limit(limit)} ROWS ONLY"
287
+ unless options[:id] == false
288
+ table_definition.primary_key(options[:primary_key] || primary_key(name))
289
+ end
290
+
291
+ yield table_definition if block_given?
292
+
293
+ # Clobs in DB2 Host have to be created after the Table with an auxiliary Table.
294
+ clob_columns = []
295
+ table_definition.columns.delete_if do |column|
296
+ if column.type && column.type.to_sym == :text
297
+ clob_columns << column; true
161
298
  end
162
- elsif limit && offset
163
- sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
164
- sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{sanitize_limit(limit) + offset}"
165
299
  end
166
- sql
300
+
301
+ drop_table(name, options) if options[:force] && table_exists?(name)
302
+
303
+ create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
304
+ create_sql << "#{quote_table_name(name)} ("
305
+ create_sql << table_definition.to_sql
306
+ create_sql << ") #{options[:options]}"
307
+ if @config[:database] && @config[:tablespace]
308
+ create_sql << " IN #{@config[:database]}.#{@config[:tablespace]}"
309
+ end
310
+
311
+ execute create_sql
312
+
313
+ # Table definition is complete only when a unique index is created on the primary_key column for DB2 V8 on zOS
314
+ # create index on id column if options[:id] is nil or id ==true
315
+ # else check if options[:primary_key]is not nil then create an unique index on that column
316
+ # TODO someone on Z/OS should test this out - also not needed for V9 ?
317
+ #primary_column = options[:id] == true ? 'id' : options[:primary_key]
318
+ #add_index(name, (primary_column || 'id').to_s, :unique => true)
319
+
320
+ clob_columns.each do |clob_column|
321
+ column_name = clob_column.name.to_s
322
+ execute "ALTER TABLE #{name} ADD COLUMN #{column_name} clob"
323
+ clob_table_name = "#{name}_#{column_name}_CD_"
324
+ if @config[:database] && @config[:lob_tablespaces]
325
+ in_lob_table_space = " IN #{@config[:database]}.#{@config[:lob_tablespaces][name.split(".")[1]]}"
326
+ end
327
+ execute "CREATE AUXILIARY TABLE #{clob_table_name} #{in_lob_table_space} STORES #{name} COLUMN #{column_name}"
328
+ execute "CREATE UNIQUE INDEX #{clob_table_name} ON #{clob_table_name};"
329
+ end
167
330
  end
331
+ private :zos_create_table
168
332
 
169
333
  def pk_and_sequence_for(table)
170
334
  # In JDBC/DB2 side, only upcase names of table and column are handled.
@@ -176,88 +340,255 @@ module ArJdbc
176
340
  keys
177
341
  end
178
342
 
179
- def quote_column_name(column_name)
180
- column_name
181
- end
343
+ # Properly quotes the various data types.
344
+ # @param value contains the data
345
+ # @param column (optional) contains info on the field
346
+ # @override
347
+ def quote(value, column = nil)
348
+ return value.quoted_id if value.respond_to?(:quoted_id)
349
+ return value if sql_literal?(value)
182
350
 
183
- def quote(value, column = nil) # :nodoc:
184
- if column && column.respond_to?(:primary) && column.primary && column.klass != String
185
- return value.to_i.to_s
186
- end
187
- if column && (column.type == :decimal || column.type == :integer) && value
188
- return value.to_s
351
+ if column
352
+ if column.respond_to?(:primary) && column.primary && column.klass != String
353
+ return value.to_i.to_s
354
+ end
355
+ if value && (column.type.to_sym == :decimal || column.type.to_sym == :integer)
356
+ return value.to_s
357
+ end
189
358
  end
359
+
360
+ column_type = column && column.type.to_sym
361
+
190
362
  case value
191
- when String
192
- if column && column.type == :binary
193
- "BLOB('#{quote_string(value)}')"
363
+ when nil then 'NULL'
364
+ when Numeric # IBM_DB doesn't accept quotes on numeric types
365
+ # if the column type is text or string, return the quote value
366
+ if column_type == :text || column_type == :string
367
+ "'#{value}'"
368
+ else
369
+ value.to_s
370
+ end
371
+ when String, ActiveSupport::Multibyte::Chars
372
+ if column_type == :binary && column.sql_type !~ /for bit data/i
373
+ if update_lob_value?(value, column)
374
+ value.nil? ? 'NULL' : BLOB_VALUE_MARKER # '@@@IBMBINARY@@@'"
375
+ else
376
+ "BLOB('#{quote_string(value)}')"
377
+ end
378
+ elsif column && column.sql_type =~ /clob/ # :text
379
+ if update_lob_value?(value, column)
380
+ value.nil? ? 'NULL' : CLOB_VALUE_MARKER # "'@@@IBMTEXT@@@'"
381
+ else
382
+ "'#{quote_string(value)}'"
383
+ end
384
+ elsif column_type == :xml
385
+ value.nil? ? 'NULL' : "'#{quote_string(value)}'" # "'<ibm>@@@IBMXML@@@</ibm>'"
194
386
  else
195
387
  "'#{quote_string(value)}'"
196
388
  end
389
+ when Symbol then "'#{quote_string(value.to_s)}'"
390
+ when Time
391
+ # AS400 doesn't support date in time column
392
+ if column_type == :time
393
+ quote_time(value)
394
+ else
395
+ super
396
+ end
197
397
  else super
198
398
  end
199
399
  end
200
400
 
201
- def quote_string(string)
202
- string.gsub(/'/, "''") # ' (for ruby-mode)
401
+ # @override
402
+ def quoted_date(value)
403
+ if value.acts_like?(:time) && value.respond_to?(:usec)
404
+ usec = sprintf("%06d", value.usec)
405
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
406
+ "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
407
+ else
408
+ super
409
+ end
410
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
411
+
412
+ def quote_time(value)
413
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
414
+ # AS400 doesn't support date in time column
415
+ "'#{value.strftime("%H:%M:%S")}'"
416
+ end
417
+
418
+ def quote_column_name(column_name)
419
+ column_name.to_s
420
+ end
421
+
422
+ def modify_types(types)
423
+ super(types)
424
+ types[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
425
+ types[:string][:limit] = 255
426
+ types[:integer][:limit] = nil
427
+ types[:boolean] = {:name => "decimal(1)"}
428
+ types
429
+ end
430
+
431
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
432
+ limit = nil if type.to_sym == :integer
433
+ super(type, limit, precision, scale)
203
434
  end
204
435
 
205
- def quoted_true
206
- '1'
436
+ # @private
437
+ VALUES_DEFAULT = 'VALUES ( DEFAULT )' # NOTE: Arel::Visitors::DB2 uses this
438
+
439
+ # @override
440
+ def empty_insert_statement_value
441
+ VALUES_DEFAULT # won't work as DB2 needs to know the column count
207
442
  end
208
443
 
209
- def quoted_false
210
- '0'
444
+ def add_column(table_name, column_name, type, options = {})
445
+ # The keyword COLUMN allows to use reserved names for columns (ex: date)
446
+ add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
447
+ add_column_options!(add_column_sql, options)
448
+ execute(add_column_sql)
449
+ end
450
+
451
+ def add_column_options!(sql, options)
452
+ # handle case of defaults for CLOB columns,
453
+ # which might get incorrect if we write LOBs in the after_save callback
454
+ if options_include_default?(options)
455
+ column = options[:column]
456
+ if column && column.type == :text
457
+ sql << " DEFAULT #{quote(options.delete(:default))}"
458
+ end
459
+ if column && column.type == :binary
460
+ # quoting required for the default value of a column :
461
+ value = options.delete(:default)
462
+ # DB2 z/OS only allows NULL or "" (empty) string as DEFAULT value
463
+ # for a BLOB column. non-empty string and non-NULL, return error!
464
+ if value.nil?
465
+ sql_value = "NULL"
466
+ else
467
+ sql_value = zos? ? "#{value}" : "BLOB('#{quote_string(value)}'"
468
+ end
469
+ sql << " DEFAULT #{sql_value}"
470
+ end
471
+ end
472
+ super
211
473
  end
212
474
 
213
- def reorg_table(table_name)
214
- unless as400?
215
- @connection.execute_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')"
475
+ # @note Only used with (non-AREL) ActiveRecord **2.3**.
476
+ # @see Arel::Visitors::DB2
477
+ def add_limit_offset!(sql, options)
478
+ limit = options[:limit]
479
+ replace_limit_offset!(sql, limit, options[:offset]) if limit
480
+ end if ::ActiveRecord::VERSION::MAJOR < 3
481
+
482
+ # @private shared with {Arel::Visitors::DB2}
483
+ def replace_limit_offset!(sql, limit, offset, orders = nil)
484
+ limit = limit.to_i
485
+
486
+ if offset # && limit
487
+ over_order_by = nil # NOTE: orders matching got reverted as it was not complete and there were no case covering it ...
488
+
489
+ start_sql = "SELECT B.* FROM (SELECT A.*, row_number() OVER (#{over_order_by}) AS internal$rownum FROM (SELECT"
490
+ end_sql = ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset.to_i}"
491
+
492
+ if sql.is_a?(String)
493
+ sql.sub!(/SELECT/i, start_sql)
494
+ sql << end_sql
495
+ else # AR 4.2 sql.class ... Arel::Collectors::Bind
496
+ sql.parts[0] = start_sql # sql.sub! /SELECT/i
497
+ sql.parts[ sql.parts.length ] = end_sql
498
+ end
499
+ else
500
+ limit_sql = limit == 1 ? " FETCH FIRST ROW ONLY" : " FETCH FIRST #{limit} ROWS ONLY"
501
+ if sql.is_a?(String)
502
+ sql << limit_sql
503
+ else # AR 4.2 sql.class ... Arel::Collectors::Bind
504
+ sql.parts[ sql.parts.length ] = limit_sql
505
+ end
216
506
  end
507
+ sql
508
+ end
509
+
510
+ # @deprecated seems not sued nor tested ?!
511
+ def runstats_for_table(tablename, priority = 10)
512
+ @connection.execute_update "call sysproc.admin_cmd('RUNSTATS ON TABLE #{tablename} WITH DISTRIBUTION AND DETAILED INDEXES ALL UTIL_IMPACT_PRIORITY #{priority}')"
513
+ end
514
+
515
+ if ::ActiveRecord::VERSION::MAJOR >= 4
516
+
517
+ def select(sql, name = nil, binds = [])
518
+ exec_query(to_sql(suble_null_test(sql), binds), name, binds)
519
+ end
520
+
521
+ else
522
+
523
+ def select(sql, name = nil, binds = [])
524
+ exec_query_raw(to_sql(suble_null_test(sql), binds), name, binds)
525
+ end
526
+
217
527
  end
218
528
 
219
- def recreate_database(name)
220
- tables.each {|table| drop_table("#{db2_schema}.#{table}")}
529
+ # @private
530
+ IS_NOT_NULL = /(!=|<>)\s*NULL/i
531
+ # @private
532
+ IS_NULL = /=\s*NULL/i
533
+
534
+ def suble_null_test(sql)
535
+ return sql unless sql.is_a?(String)
536
+ # DB2 does not like "= NULL", "!= NULL", or "<> NULL" :
537
+ sql = sql.dup
538
+ sql.gsub! IS_NOT_NULL, 'IS NOT NULL'
539
+ sql.gsub! IS_NULL, 'IS NULL'
540
+ sql
541
+ end
542
+ private :suble_null_test
543
+
544
+ def add_index(table_name, column_name, options = {})
545
+ if ! zos? || ( table_name.to_s == ActiveRecord::Migrator.schema_migrations_table_name.to_s )
546
+ column_name = column_name.to_s if column_name.is_a?(Symbol)
547
+ super
548
+ else
549
+ statement = 'CREATE'
550
+ statement << ' UNIQUE ' if options[:unique]
551
+ statement << " INDEX #{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
552
+ statement << " ON #{table_name}(#{column_name})"
553
+
554
+ execute statement
555
+ end
221
556
  end
222
557
 
223
- def remove_index(table_name, options = { })
224
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
558
+ # @override
559
+ def remove_index!(table_name, index_name)
560
+ execute "DROP INDEX #{quote_column_name(index_name)}"
225
561
  end
226
562
 
227
563
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
228
564
  # ...not supported on IBM i, so we raise in this case
229
565
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
230
- if as400?
231
- raise NotImplementedError, "rename_column is not supported on IBM i"
232
- else
233
- execute "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
234
- reorg_table(table_name)
235
- end
566
+ sql = "ALTER TABLE #{table_name} RENAME COLUMN #{column_name} TO #{new_column_name}"
567
+ execute_table_change(sql, table_name, 'Rename Column')
236
568
  end
237
569
 
238
570
  def change_column_null(table_name, column_name, null)
239
571
  if null
240
- execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
572
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP NOT NULL"
241
573
  else
242
- execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
574
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET NOT NULL"
243
575
  end
244
- reorg_table(table_name)
576
+ execute_table_change(sql, table_name, 'Change Column')
245
577
  end
246
578
 
247
579
  def change_column_default(table_name, column_name, default)
248
580
  if default.nil?
249
- execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
581
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} DROP DEFAULT"
250
582
  else
251
- execute_and_auto_confirm "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
583
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
252
584
  end
253
- reorg_table(table_name)
585
+ execute_table_change(sql, table_name, 'Change Column')
254
586
  end
255
587
 
256
588
  def change_column(table_name, column_name, type, options = {})
257
589
  data_type = type_to_sql(type, options[:limit], options[:precision], options[:scale])
258
590
  sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DATA TYPE #{data_type}"
259
- as400? ? execute_and_auto_confirm(sql) : execute(sql)
260
- reorg_table(table_name)
591
+ execute_table_change(sql, table_name, 'Change Column')
261
592
 
262
593
  if options.include?(:default) and options.include?(:null)
263
594
  # which to run first?
@@ -275,135 +606,184 @@ module ArJdbc
275
606
  end
276
607
  end
277
608
 
278
- # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
279
- def remove_column(table_name, column_name) #:nodoc:
280
- sql = "ALTER TABLE #{table_name} DROP COLUMN #{column_name}"
609
+ if ActiveRecord::VERSION::MAJOR >= 4
281
610
 
282
- as400? ? execute_and_auto_confirm(sql) : execute(sql)
283
- reorg_table(table_name)
611
+ def remove_column(table_name, column_name, type = nil, options = {})
612
+ db2_remove_column(table_name, column_name)
284
613
  end
285
614
 
286
- # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
287
- def rename_table(name, new_name) #:nodoc:
288
- execute "RENAME TABLE #{name} TO #{new_name}"
289
- reorg_table(new_name)
615
+ else
616
+
617
+ def remove_column(table_name, *column_names)
618
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
619
+ outcome = nil
620
+ column_names = column_names.flatten
621
+ for column_name in column_names
622
+ outcome = db2_remove_column(table_name, column_name)
623
+ end
624
+ column_names.size == 1 ? outcome : nil
625
+ end
626
+
627
+ end
628
+
629
+ def rename_table(name, new_name)
630
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
631
+ execute_table_change("RENAME TABLE #{name} TO #{new_name}", new_name, 'Rename Table')
290
632
  end
291
633
 
292
634
  def tables
293
- @connection.tables(nil, db2_schema, nil, ["TABLE"])
635
+ @connection.tables(nil, schema)
294
636
  end
295
637
 
296
- # only record precision and scale for types that can set
297
- # them via CREATE TABLE:
638
+ # only record precision and scale for types that can set them via CREATE TABLE:
298
639
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
299
- HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
640
+
641
+ HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) # TIMESTAMP
300
642
  HAVE_PRECISION = %w(DECIMAL NUMERIC)
301
643
  HAVE_SCALE = %w(DECIMAL NUMERIC)
302
644
 
303
645
  def columns(table_name, name = nil)
304
- cols = @connection.columns(table_name, name, db2_schema)
646
+ columns = @connection.columns_internal(table_name.to_s, nil, schema) # catalog == nil
305
647
 
648
+ if zos?
649
+ # Remove the mighty db2_generated_rowid_for_lobs from the list of columns
650
+ columns = columns.reject { |col| "db2_generated_rowid_for_lobs" == col.name }
651
+ end
306
652
  # scrub out sizing info when CREATE TABLE doesn't support it
307
653
  # but JDBC reports it (doh!)
308
- for col in cols
309
- base_sql_type = col.sql_type.sub(/\(.*/, "").upcase
310
- col.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
311
- col.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
312
- #col.scale = nil unless HAVE_SCALE.include?(base_sql_type)
654
+ for column in columns
655
+ base_sql_type = column.sql_type.sub(/\(.*/, "").upcase
656
+ column.limit = nil unless HAVE_LIMIT.include?(base_sql_type)
657
+ column.precision = nil unless HAVE_PRECISION.include?(base_sql_type)
658
+ #column.scale = nil unless HAVE_SCALE.include?(base_sql_type)
313
659
  end
314
660
 
315
- cols
661
+ columns
316
662
  end
317
663
 
318
664
  def indexes(table_name, name = nil)
319
- @connection.indexes(table_name, name, db2_schema)
665
+ @connection.indexes(table_name, name, schema)
320
666
  end
321
667
 
322
- def add_quotes(name)
323
- return name unless name
324
- %Q{"#{name}"}
668
+ def recreate_database(name = nil, options = {})
669
+ drop_database(name)
325
670
  end
326
671
 
327
- def strip_quotes(str)
328
- return str unless str
329
- return str unless /^(["']).*\1$/ =~ str
330
- str[1..-2]
672
+ def drop_database(name = nil)
673
+ tables.each { |table| drop_table("#{table}") }
331
674
  end
332
675
 
333
- def expand_double_quotes(name)
334
- return name unless name && name['"']
335
- name.gsub(/"/,'""')
676
+ def truncate(table_name, name = nil)
677
+ execute "TRUNCATE TABLE #{quote_table_name(table_name)} IMMEDIATE", name
336
678
  end
337
679
 
338
- def structure_dump #:nodoc:
339
- definition=""
340
- rs = @connection.connection.meta_data.getTables(nil,db2_schema.upcase,nil,["TABLE"].to_java(:string))
341
- while rs.next
342
- tname = rs.getString(3)
343
- definition << "CREATE TABLE #{tname} (\n"
344
- rs2 = @connection.connection.meta_data.getColumns(nil,db2_schema.upcase,tname,nil)
345
- first_col = true
346
- while rs2.next
347
- col_name = add_quotes(rs2.getString(4));
348
- default = ""
349
- d1 = rs2.getString(13)
350
- # IBM i (as400 toolbox driver) will return an empty string if there is no default
351
- if @config[:url] =~ /^jdbc:as400:/
352
- default = !d1.blank? ? " DEFAULT #{d1}" : ""
353
- else
354
- default = d1 ? " DEFAULT #{d1}" : ""
355
- end
680
+ # @override
681
+ def supports_views?; true end
356
682
 
357
- type = rs2.getString(6)
358
- col_precision = rs2.getString(7)
359
- col_scale = rs2.getString(9)
360
- col_size = ""
361
- if HAVE_SCALE.include?(type) and col_scale
362
- col_size = "(#{col_precision},#{col_scale})"
363
- elsif (HAVE_LIMIT + HAVE_PRECISION).include?(type) and col_precision
364
- col_size = "(#{col_precision})"
365
- end
366
- nulling = (rs2.getString(18) == 'NO' ? " NOT NULL" : "")
367
- create_col_string = add_quotes(expand_double_quotes(strip_quotes(col_name))) +
368
- " " +
369
- type +
370
- col_size +
371
- "" +
372
- nulling +
373
- default
374
- if !first_col
375
- create_col_string = ",\n #{create_col_string}"
376
- else
377
- create_col_string = " #{create_col_string}"
378
- end
683
+ def execute_table_change(sql, table_name, name = nil)
684
+ outcome = execute(sql, name)
685
+ reorg_table(table_name, name)
686
+ outcome
687
+ end
688
+ protected :execute_table_change
379
689
 
380
- definition << create_col_string
690
+ def reorg_table(table_name, name = nil)
691
+ exec_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')", name, []
692
+ end
693
+ private :reorg_table
381
694
 
382
- first_col = false
383
- end
384
- definition << ");\n\n"
695
+ # alias_method :execute_and_auto_confirm, :execute
696
+
697
+ # Returns the value of an identity column of the last *INSERT* statement
698
+ # made over this connection.
699
+ # @note Check the *IDENTITY_VAL_LOCAL* function for documentation.
700
+ # @return [Fixnum]
701
+ def last_insert_id
702
+ @connection.identity_val_local
703
+ end
704
+
705
+ # NOTE: only setup query analysis on AR <= 3.0 since on 3.1 {#exec_query},
706
+ # {#exec_insert} will be used for AR generated queries/inserts etc.
707
+ # Also there's prepared statement support and {#execute} is meant to stay
708
+ # as a way of running non-prepared SQL statements (returning raw results).
709
+ if ActiveRecord::VERSION::MAJOR < 3 ||
710
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
711
+
712
+ def _execute(sql, name = nil)
713
+ if self.class.select?(sql)
714
+ @connection.execute_query_raw(sql)
715
+ elsif self.class.insert?(sql)
716
+ @connection.execute_insert(sql) || last_insert_id
717
+ else
718
+ @connection.execute_update(sql)
385
719
  end
386
- definition
387
720
  end
721
+ private :_execute
388
722
 
389
- private
723
+ end
724
+
725
+ DRIVER_NAME = 'com.ibm.db2.jcc.DB2Driver'.freeze
726
+
727
+ # @private
728
+ def zos?
729
+ @zos = nil unless defined? @zos
730
+ return @zos unless @zos.nil?
731
+ @zos =
732
+ if url = config[:url]
733
+ !!( url =~ /^jdbc:db2j:net:/ && config[:driver] == DRIVER_NAME )
734
+ else
735
+ nil
736
+ end
737
+ end
738
+
739
+ # @private
740
+ # @deprecated no longer used
390
741
  def as400?
391
- @config[:url] =~ /^jdbc:as400:/
742
+ false
743
+ end
744
+
745
+ def schema
746
+ db2_schema
747
+ end
748
+
749
+ def schema=(schema)
750
+ set_schema(@db2_schema = schema) if db2_schema != schema
751
+ end
752
+
753
+ private
754
+
755
+ def set_schema(schema)
756
+ execute("SET SCHEMA #{schema}")
392
757
  end
393
758
 
394
759
  def db2_schema
395
- if @config[:schema].blank?
396
- if as400?
397
- # AS400 implementation takes schema from library name (last part of url)
398
- schema = @config[:url].split('/').last.strip
399
- (schema[-1..-1] == ";") ? schema.chop : schema
760
+ @db2_schema = false unless defined? @db2_schema
761
+ return @db2_schema if @db2_schema != false
762
+ schema = config[:schema]
763
+ @db2_schema =
764
+ if schema then schema
765
+ elsif config[:jndi] || config[:data_source]
766
+ nil # let JNDI worry about schema
400
767
  else
401
768
  # LUW implementation uses schema name of username by default
402
- @config[:username] or ENV['USER']
769
+ config[:username] || ENV['USER']
403
770
  end
404
- else
405
- @config[:schema]
406
- end
407
771
  end
772
+
773
+ def db2_remove_column(table_name, column_name)
774
+ sql = "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
775
+ execute_table_change(sql, table_name, 'Remove Column')
776
+ end
777
+
778
+ end
779
+ end
780
+
781
+ module ActiveRecord::ConnectionAdapters
782
+
783
+ remove_const(:DB2Column) if const_defined?(:DB2Column)
784
+
785
+ class DB2Column < JdbcColumn
786
+ include ::ArJdbc::DB2::Column
408
787
  end
788
+
409
789
  end