activerecord-jdbc-adapter 1.3.0.beta2 → 1.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/.gitignore +14 -8
  2. data/.travis.yml +40 -31
  3. data/.yardopts +4 -0
  4. data/Appraisals +2 -5
  5. data/CONTRIBUTING.md +46 -0
  6. data/Gemfile +21 -4
  7. data/Gemfile.lock +42 -17
  8. data/{History.txt → History.md} +142 -75
  9. data/README.md +102 -104
  10. data/RUNNING_TESTS.md +76 -0
  11. data/Rakefile.jdbc +20 -0
  12. data/activerecord-jdbc-adapter.gemspec +35 -18
  13. data/gemfiles/rails23.gemfile +4 -3
  14. data/gemfiles/rails23.gemfile.lock +9 -6
  15. data/gemfiles/rails30.gemfile +4 -3
  16. data/gemfiles/rails30.gemfile.lock +9 -6
  17. data/gemfiles/rails31.gemfile +4 -3
  18. data/gemfiles/rails31.gemfile.lock +9 -6
  19. data/gemfiles/rails32.gemfile +4 -3
  20. data/gemfiles/rails32.gemfile.lock +17 -14
  21. data/gemfiles/rails40.gemfile +5 -5
  22. data/gemfiles/rails40.gemfile.lock +17 -69
  23. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  25. data/lib/arel/visitors/compat.rb +22 -3
  26. data/lib/arel/visitors/db2.rb +8 -4
  27. data/lib/arel/visitors/derby.rb +14 -13
  28. data/lib/arel/visitors/firebird.rb +5 -4
  29. data/lib/arel/visitors/hsqldb.rb +11 -9
  30. data/lib/arel/visitors/sql_server.rb +89 -61
  31. data/lib/arjdbc.rb +1 -1
  32. data/lib/arjdbc/db2/adapter.rb +181 -212
  33. data/lib/arjdbc/db2/as400.rb +31 -18
  34. data/lib/arjdbc/db2/column.rb +167 -0
  35. data/lib/arjdbc/db2/connection_methods.rb +2 -0
  36. data/lib/arjdbc/derby/adapter.rb +206 -107
  37. data/lib/arjdbc/derby/connection_methods.rb +4 -9
  38. data/lib/arjdbc/firebird.rb +1 -0
  39. data/lib/arjdbc/firebird/adapter.rb +202 -64
  40. data/lib/arjdbc/firebird/connection_methods.rb +20 -0
  41. data/lib/arjdbc/h2/adapter.rb +56 -36
  42. data/lib/arjdbc/hsqldb/adapter.rb +99 -68
  43. data/lib/arjdbc/jdbc/adapter.rb +474 -265
  44. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  45. data/lib/arjdbc/jdbc/adapter_require.rb +8 -7
  46. data/lib/arjdbc/jdbc/arel_support.rb +132 -0
  47. data/lib/arjdbc/jdbc/base_ext.rb +8 -7
  48. data/lib/arjdbc/jdbc/callbacks.rb +16 -10
  49. data/lib/arjdbc/jdbc/column.rb +25 -3
  50. data/lib/arjdbc/jdbc/connection.rb +28 -55
  51. data/lib/arjdbc/jdbc/extension.rb +14 -14
  52. data/lib/arjdbc/jdbc/java.rb +6 -3
  53. data/lib/arjdbc/jdbc/jdbc.rake +1 -1
  54. data/lib/arjdbc/jdbc/quoted_primary_key.rb +2 -2
  55. data/lib/arjdbc/jdbc/rake_tasks.rb +1 -1
  56. data/lib/arjdbc/jdbc/type_converter.rb +5 -2
  57. data/lib/arjdbc/mssql/adapter.rb +160 -280
  58. data/lib/arjdbc/mssql/column.rb +182 -0
  59. data/lib/arjdbc/mssql/connection_methods.rb +37 -4
  60. data/lib/arjdbc/mssql/explain_support.rb +13 -21
  61. data/lib/arjdbc/mssql/limit_helpers.rb +79 -42
  62. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  63. data/lib/arjdbc/mssql/utils.rb +11 -11
  64. data/lib/arjdbc/mysql/adapter.rb +165 -247
  65. data/lib/arjdbc/mysql/column.rb +123 -0
  66. data/lib/arjdbc/mysql/connection_methods.rb +3 -6
  67. data/lib/arjdbc/oracle/adapter.rb +282 -288
  68. data/lib/arjdbc/oracle/column.rb +122 -0
  69. data/lib/arjdbc/oracle/connection_methods.rb +3 -0
  70. data/lib/arjdbc/postgresql/adapter.rb +336 -574
  71. data/lib/arjdbc/postgresql/column.rb +458 -0
  72. data/lib/arjdbc/postgresql/connection_methods.rb +1 -2
  73. data/lib/arjdbc/postgresql/schema_creation.rb +38 -0
  74. data/lib/arjdbc/sqlite3/adapter.rb +189 -145
  75. data/lib/arjdbc/sqlite3/explain_support.rb +1 -1
  76. data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +8 -8
  77. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  78. data/lib/arjdbc/util/table_copier.rb +110 -0
  79. data/lib/arjdbc/version.rb +6 -7
  80. data/pom.xml +56 -2
  81. data/rakelib/02-test.rake +72 -83
  82. data/rakelib/db.rake +29 -17
  83. data/src/java/arjdbc/ArJdbcModule.java +21 -18
  84. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +84 -12
  85. data/src/java/arjdbc/derby/DerbyModule.java +140 -143
  86. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +58 -7
  87. data/src/java/arjdbc/h2/H2Module.java +43 -0
  88. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +7 -6
  89. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1223 -648
  90. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +24 -23
  91. data/src/java/arjdbc/mysql/MySQLModule.java +33 -32
  92. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +147 -30
  93. data/src/java/arjdbc/oracle/OracleModule.java +13 -13
  94. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +114 -6
  95. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +166 -36
  96. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +101 -19
  97. data/src/java/arjdbc/util/QuotingUtils.java +19 -19
  98. metadata +240 -394
  99. data/bench/bench_attributes.rb +0 -13
  100. data/bench/bench_attributes_new.rb +0 -14
  101. data/bench/bench_create.rb +0 -12
  102. data/bench/bench_find_all.rb +0 -12
  103. data/bench/bench_find_all_mt.rb +0 -25
  104. data/bench/bench_model.rb +0 -85
  105. data/bench/bench_new.rb +0 -12
  106. data/bench/bench_new_valid.rb +0 -12
  107. data/bench/bench_valid.rb +0 -13
  108. data/lib/arel/engines/sql/compilers/db2_compiler.rb +0 -9
  109. data/lib/arel/engines/sql/compilers/derby_compiler.rb +0 -6
  110. data/lib/arel/engines/sql/compilers/h2_compiler.rb +0 -6
  111. data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +0 -15
  112. data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +0 -6
  113. data/lib/arel/engines/sql/compilers/mssql_compiler.rb +0 -46
  114. data/lib/arjdbc/jdbc/missing_functionality_helper.rb +0 -98
  115. data/lib/arjdbc/mssql/lock_helpers.rb +0 -76
  116. data/lib/arjdbc/mssql/tsql_methods.rb +0 -58
  117. data/lib/arjdbc/postgresql/column_cast.rb +0 -134
  118. data/test/activerecord/connections/native_jdbc_mysql/connection.rb +0 -25
  119. data/test/activerecord/jall.sh +0 -7
  120. data/test/activerecord/jtest.sh +0 -3
  121. data/test/assets/flowers.jpg +0 -0
  122. data/test/binary.rb +0 -67
  123. data/test/db/db2.rb +0 -43
  124. data/test/db/db2/binary_test.rb +0 -6
  125. data/test/db/db2/has_many_through_test.rb +0 -6
  126. data/test/db/db2/rake_test.rb +0 -82
  127. data/test/db/db2/rake_test_data.sql +0 -35
  128. data/test/db/db2/reset_column_information_test.rb +0 -5
  129. data/test/db/db2/serialize_test.rb +0 -6
  130. data/test/db/db2/simple_test.rb +0 -81
  131. data/test/db/db2/test_helper.rb +0 -6
  132. data/test/db/db2/unit_test.rb +0 -73
  133. data/test/db/derby.rb +0 -12
  134. data/test/db/derby/binary_test.rb +0 -6
  135. data/test/db/derby/migration_test.rb +0 -74
  136. data/test/db/derby/rake_test.rb +0 -96
  137. data/test/db/derby/reset_column_information_test.rb +0 -6
  138. data/test/db/derby/row_locking_test.rb +0 -20
  139. data/test/db/derby/schema_dump_test.rb +0 -5
  140. data/test/db/derby/serialize_test.rb +0 -6
  141. data/test/db/derby/simple_test.rb +0 -173
  142. data/test/db/derby/test_helper.rb +0 -6
  143. data/test/db/derby/unit_test.rb +0 -32
  144. data/test/db/derby/xml_column_test.rb +0 -17
  145. data/test/db/h2.rb +0 -11
  146. data/test/db/h2/binary_test.rb +0 -6
  147. data/test/db/h2/change_column_test.rb +0 -68
  148. data/test/db/h2/identity_column_test.rb +0 -35
  149. data/test/db/h2/offset_test.rb +0 -49
  150. data/test/db/h2/rake_test.rb +0 -98
  151. data/test/db/h2/schema_dump_test.rb +0 -29
  152. data/test/db/h2/serialize_test.rb +0 -6
  153. data/test/db/h2/simple_test.rb +0 -56
  154. data/test/db/hsqldb.rb +0 -11
  155. data/test/db/hsqldb/binary_test.rb +0 -6
  156. data/test/db/hsqldb/rake_test.rb +0 -101
  157. data/test/db/hsqldb/schema_dump_test.rb +0 -19
  158. data/test/db/hsqldb/serialize_test.rb +0 -6
  159. data/test/db/hsqldb/simple_test.rb +0 -17
  160. data/test/db/informix.rb +0 -13
  161. data/test/db/jdbc.rb +0 -16
  162. data/test/db/jdbc_derby.rb +0 -14
  163. data/test/db/jdbc_h2.rb +0 -17
  164. data/test/db/jdbc_mysql.rb +0 -13
  165. data/test/db/jdbc_postgres.rb +0 -23
  166. data/test/db/jndi_config.rb +0 -32
  167. data/test/db/jndi_pooled_config.rb +0 -32
  168. data/test/db/mssql.rb +0 -11
  169. data/test/db/mssql/binary_test.rb +0 -6
  170. data/test/db/mssql/exec_proc_test.rb +0 -46
  171. data/test/db/mssql/identity_insert_test.rb +0 -18
  172. data/test/db/mssql/ignore_system_views_test.rb +0 -40
  173. data/test/db/mssql/limit_offset_test.rb +0 -190
  174. data/test/db/mssql/multibyte_test.rb +0 -16
  175. data/test/db/mssql/multiple_connections_test.rb +0 -71
  176. data/test/db/mssql/rake_test.rb +0 -143
  177. data/test/db/mssql/reset_column_information_test.rb +0 -6
  178. data/test/db/mssql/row_locking_test.rb +0 -7
  179. data/test/db/mssql/serialize_test.rb +0 -6
  180. data/test/db/mssql/simple_test.rb +0 -140
  181. data/test/db/mssql/transaction_test.rb +0 -6
  182. data/test/db/mssql/types_test.rb +0 -205
  183. data/test/db/mssql/unit_test.rb +0 -249
  184. data/test/db/mysql.rb +0 -4
  185. data/test/db/mysql/_rails_test_mysql.32.out +0 -6585
  186. data/test/db/mysql/binary_test.rb +0 -6
  187. data/test/db/mysql/connection_test.rb +0 -51
  188. data/test/db/mysql/index_length_test.rb +0 -58
  189. data/test/db/mysql/multibyte_test.rb +0 -10
  190. data/test/db/mysql/nonstandard_primary_key_test.rb +0 -39
  191. data/test/db/mysql/rake_test.rb +0 -97
  192. data/test/db/mysql/reset_column_information_test.rb +0 -6
  193. data/test/db/mysql/schema_dump_test.rb +0 -228
  194. data/test/db/mysql/serialize_test.rb +0 -6
  195. data/test/db/mysql/simple_test.rb +0 -187
  196. data/test/db/mysql/statement_escaping_test.rb +0 -46
  197. data/test/db/mysql/transaction_test.rb +0 -6
  198. data/test/db/mysql/types_test.rb +0 -30
  199. data/test/db/mysql/unit_test.rb +0 -93
  200. data/test/db/mysql_config.rb +0 -7
  201. data/test/db/oracle.rb +0 -27
  202. data/test/db/oracle/binary_test.rb +0 -6
  203. data/test/db/oracle/limit_test.rb +0 -24
  204. data/test/db/oracle/multibyte_test.rb +0 -22
  205. data/test/db/oracle/rake_test.rb +0 -100
  206. data/test/db/oracle/reset_column_information_test.rb +0 -6
  207. data/test/db/oracle/serialize_test.rb +0 -6
  208. data/test/db/oracle/simple_test.rb +0 -140
  209. data/test/db/oracle/specific_test.rb +0 -180
  210. data/test/db/oracle/transaction_test.rb +0 -31
  211. data/test/db/oracle/unit_test.rb +0 -31
  212. data/test/db/postgres.rb +0 -11
  213. data/test/db/postgres/_rails_test_postgres.32.out +0 -6405
  214. data/test/db/postgres/a_custom_primary_key_test.rb +0 -50
  215. data/test/db/postgres/active_schema_unit_test.rb +0 -68
  216. data/test/db/postgres/array_type_test.rb +0 -101
  217. data/test/db/postgres/binary_test.rb +0 -6
  218. data/test/db/postgres/connection_test.rb +0 -63
  219. data/test/db/postgres/data_types_test.rb +0 -703
  220. data/test/db/postgres/hstore_test.rb +0 -200
  221. data/test/db/postgres/information_schema_leak_test.rb +0 -30
  222. data/test/db/postgres/json_test.rb +0 -86
  223. data/test/db/postgres/ltree_test.rb +0 -51
  224. data/test/db/postgres/mixed_case_test.rb +0 -29
  225. data/test/db/postgres/native_types_test.rb +0 -124
  226. data/test/db/postgres/rake_test.rb +0 -117
  227. data/test/db/postgres/reserved_test.rb +0 -22
  228. data/test/db/postgres/reset_column_information_test.rb +0 -6
  229. data/test/db/postgres/row_locking_test.rb +0 -21
  230. data/test/db/postgres/schema_dump_test.rb +0 -95
  231. data/test/db/postgres/schema_test.rb +0 -115
  232. data/test/db/postgres/simple_test.rb +0 -260
  233. data/test/db/postgres/table_alias_length_test.rb +0 -16
  234. data/test/db/postgres/transaction_test.rb +0 -6
  235. data/test/db/postgres/unit_test.rb +0 -31
  236. data/test/db/postgres_config.rb +0 -10
  237. data/test/db/sqlite3.rb +0 -6
  238. data/test/db/sqlite3/_rails_test_sqlite3.32.out +0 -6274
  239. data/test/db/sqlite3/has_many_though_test.rb +0 -6
  240. data/test/db/sqlite3/rake_test.rb +0 -71
  241. data/test/db/sqlite3/reset_column_information_test.rb +0 -6
  242. data/test/db/sqlite3/schema_dump_test.rb +0 -6
  243. data/test/db/sqlite3/serialize_test.rb +0 -6
  244. data/test/db/sqlite3/simple_test.rb +0 -268
  245. data/test/db/sqlite3/transaction_test.rb +0 -32
  246. data/test/db/sqlite3/type_conversion_test.rb +0 -104
  247. data/test/has_many_through.rb +0 -61
  248. data/test/informix_simple_test.rb +0 -48
  249. data/test/jdbc/db2.rb +0 -36
  250. data/test/jdbc/oracle.rb +0 -34
  251. data/test/jdbc_column_test.rb +0 -23
  252. data/test/jdbc_common.rb +0 -16
  253. data/test/jdbc_connection_test.rb +0 -196
  254. data/test/jndi_callbacks_test.rb +0 -33
  255. data/test/jndi_test.rb +0 -55
  256. data/test/manualTestDatabase.rb +0 -191
  257. data/test/models/add_not_null_column_to_table.rb +0 -9
  258. data/test/models/auto_id.rb +0 -15
  259. data/test/models/binary.rb +0 -18
  260. data/test/models/custom_pk_name.rb +0 -15
  261. data/test/models/data_types.rb +0 -40
  262. data/test/models/entry.rb +0 -41
  263. data/test/models/mixed_case.rb +0 -22
  264. data/test/models/reserved_word.rb +0 -15
  265. data/test/models/rights_and_roles.rb +0 -57
  266. data/test/models/string_id.rb +0 -17
  267. data/test/models/thing.rb +0 -17
  268. data/test/models/topic.rb +0 -32
  269. data/test/models/validates_uniqueness_of_string.rb +0 -19
  270. data/test/rails/mysql.rb +0 -13
  271. data/test/rails/sqlite3/version.rb +0 -6
  272. data/test/rails_stub.rb +0 -31
  273. data/test/rake_test_support.rb +0 -298
  274. data/test/row_locking.rb +0 -102
  275. data/test/schema_dump.rb +0 -182
  276. data/test/serialize.rb +0 -275
  277. data/test/shared_helper.rb +0 -35
  278. data/test/simple.rb +0 -1317
  279. data/test/sybase_jtds_simple_test.rb +0 -28
  280. data/test/sybase_reset_column_information_test.rb +0 -6
  281. data/test/test_helper.rb +0 -304
  282. data/test/transaction.rb +0 -109
@@ -0,0 +1 @@
1
+ require 'arjdbc/firebird'
@@ -0,0 +1 @@
1
+ require 'arjdbc/mssql'
@@ -1,13 +1,32 @@
1
1
  module Arel
2
2
  module Visitors
3
3
  module ArJdbcCompat
4
+
5
+ protected
6
+
7
+ if ToSql.instance_method('visit').arity == 1
8
+ def do_visit(x, a); visit(x); end # a = nil
9
+ else # > AREL 4.0
10
+ def do_visit(x, a); visit(x, a); end
11
+ end
12
+
13
+ if ToSql.instance_method('visit_Arel_Nodes_SelectCore').arity == 1
14
+ def do_visit_select_core(x, a) # a = nil
15
+ visit_Arel_Nodes_SelectCore(x)
16
+ end
17
+ else # > AREL 4.0
18
+ def do_visit_select_core(x, a)
19
+ visit_Arel_Nodes_SelectCore(x, a)
20
+ end
21
+ end
22
+
23
+ private
24
+
4
25
  def limit_for(limit_or_node)
5
26
  limit_or_node.respond_to?(:expr) ? limit_or_node.expr.to_i : limit_or_node
6
27
  end
7
- end
8
28
 
9
- class ToSql
10
- include ArJdbcCompat
11
29
  end
30
+ ToSql.send(:include, ArJdbcCompat)
12
31
  end
13
32
  end
@@ -3,12 +3,15 @@ require 'arel/visitors/compat'
3
3
  module Arel
4
4
  module Visitors
5
5
  class DB2 < Arel::Visitors::ToSql
6
- def visit_Arel_Nodes_SelectStatement o
7
- add_limit_offset([o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
8
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
9
- ].compact.join(' '), o)
6
+
7
+ def visit_Arel_Nodes_SelectStatement o, a = nil
8
+ sql = o.cores.map { |x| do_visit_select_core x, a }.join
9
+ sql << " ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}" unless o.orders.empty?
10
+ add_limit_offset(sql, o)
10
11
  end
11
12
 
13
+ private
14
+
12
15
  def add_limit_offset(sql, o)
13
16
  if o.offset && o.offset.value && o.limit && o.limit.value
14
17
  @connection.replace_limit_offset_for_arel! o, sql
@@ -16,6 +19,7 @@ module Arel
16
19
  @connection.replace_limit_offset! sql, limit_for(o.limit), o.offset && o.offset.value
17
20
  end
18
21
  end
22
+
19
23
  end
20
24
  end
21
25
  end
@@ -3,30 +3,31 @@ require 'arel/visitors/compat'
3
3
  module Arel
4
4
  module Visitors
5
5
  class Derby < Arel::Visitors::ToSql
6
- def visit_Arel_Nodes_SelectStatement o
7
- [
8
- o.cores.map { |x| visit(x) }.join,
9
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
10
- (visit(o.offset) if o.offset),
11
- (visit(o.limit) if o.limit),
12
- (visit(o.lock) if o.lock),
13
- ].compact.join ' '
6
+
7
+ def visit_Arel_Nodes_SelectStatement o, a = nil
8
+ sql = o.cores.map { |x| do_visit(x, a) }.join
9
+ sql << " ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
10
+ sql << " #{do_visit o.offset, a}" if o.offset
11
+ sql << " #{do_visit o.limit, a}" if o.limit
12
+ sql << " #{do_visit o.lock, a}" if o.lock
13
+ sql
14
14
  end
15
15
 
16
- def visit_Arel_Nodes_Limit o
16
+ def visit_Arel_Nodes_Limit o, a = nil
17
17
  "FETCH FIRST #{limit_for(o)} ROWS ONLY"
18
18
  end
19
19
 
20
- def visit_Arel_Nodes_Offset o
21
- "OFFSET #{visit o.value} ROWS"
20
+ def visit_Arel_Nodes_Offset o, a = nil
21
+ "OFFSET #{do_visit o.value, a} ROWS"
22
22
  end
23
23
 
24
24
  # This generates SELECT...FOR UPDATE, but it will only work if the
25
25
  # current transaction isolation level is set to SERIALIZABLE. Otherwise,
26
26
  # locks aren't held for the entire transaction.
27
- def visit_Arel_Nodes_Lock o
28
- visit o.expr
27
+ def visit_Arel_Nodes_Lock o, a = nil
28
+ do_visit o.expr, a
29
29
  end
30
+
30
31
  end
31
32
  end
32
33
  end
@@ -3,15 +3,16 @@ require 'arel/visitors/compat'
3
3
  module Arel
4
4
  module Visitors
5
5
  class Firebird < Arel::Visitors::ToSql
6
- def visit_Arel_Nodes_SelectStatement o
6
+
7
+ def visit_Arel_Nodes_SelectStatement o, a = nil
7
8
  lim_off = [
8
- ("FIRST #{visit(o.limit.expr)}" if o.limit),
9
- ("SKIP #{visit(o.offset.expr)}" if o.offset)
9
+ ("FIRST #{do_visit o.limit.expr, a}" if o.limit),
10
+ ("SKIP #{do_visit o.offset.expr, a}" if o.offset)
10
11
  ].compact.join(' ').strip
11
12
 
12
13
  sql = [
13
14
  o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
14
- ("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
15
+ ("ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}" unless o.orders.empty?),
15
16
  ].compact.join ' '
16
17
 
17
18
  sql.sub!(/\A(\s*SELECT\s)/i, '\&' + lim_off + ' ') unless lim_off.empty?
@@ -3,25 +3,27 @@ require 'arel/visitors/compat'
3
3
  module Arel
4
4
  module Visitors
5
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 ' '
6
+
7
+ def visit_Arel_Nodes_SelectStatement o, a = nil
8
+ sql = limit_offset(o.cores.map { |x| do_visit_select_core x, a }.join, o)
9
+ sql << " ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}" unless o.orders.empty?
10
+ sql
11
11
  end
12
12
 
13
+ private
14
+
13
15
  def limit_offset sql, o
14
16
  offset = o.offset || 0
15
- offset = offset.expr unless(offset.nil? or offset == 0)
16
- bef = sql[7..-1]
17
+ offset = offset.expr unless (offset.nil? || offset == 0)
17
18
  if limit = o.limit
18
- "SELECT LIMIT #{offset} #{limit_for(limit)} #{bef}"
19
+ "SELECT LIMIT #{offset} #{limit_for(limit)} #{sql[7..-1]}"
19
20
  elsif offset > 0
20
- "SELECT LIMIT #{offset} 0 #{bef}"
21
+ "SELECT LIMIT #{offset} 0 #{sql[7..-1]}" # removes "SELECT "
21
22
  else
22
23
  sql
23
24
  end
24
25
  end
26
+
25
27
  end
26
28
  end
27
29
  end
@@ -2,93 +2,121 @@ require 'arel/visitors/compat'
2
2
 
3
3
  module Arel
4
4
  module Visitors
5
- class SQLServer < ToSql
5
+ # @note AREL set's up `Arel::Visitors::MSSQL` but we should not use that one !
6
+ class SQLServer < const_defined?(:MSSQL) ? MSSQL : ToSql
6
7
 
7
- # Need to mimic the subquery logic in ARel 1.x for select count with limit
8
- # See arel/engines/sql/compilers/mssql_compiler.rb for details
9
8
  def visit_Arel_Nodes_SelectStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
10
9
  o, a = args.first, args.last
11
-
12
- if ! o.limit && o.offset
13
- raise ActiveRecord::ActiveRecordError, "You must specify :limit with :offset."
10
+
11
+ if ! o.limit && ! o.offset
12
+ return super
13
+ elsif ! o.limit && o.offset
14
+ raise ActiveRecord::ActiveRecordError, "must specify :limit with :offset"
15
+ end
16
+
17
+ unless o.orders.empty?
18
+ select_order_by = "ORDER BY #{o.orders.map { |x| do_visit x, a }.join(', ')}"
14
19
  end
15
-
16
- order = "ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?
17
- if o.limit
18
- if select_count?(o)
19
- subquery = true
20
- sql = o.cores.map do |x|
21
- x = x.dup
22
- x.projections = [Arel::Nodes::SqlLiteral.new("*")]
23
- do_visit_select_core(x, a)
24
- end.join
20
+
21
+ select_count = false
22
+ sql = o.cores.map do |x|
23
+ x = x.dup
24
+ order_by = select_order_by || determine_order_by(x, a)
25
+ if select_count? x
26
+ p = order_by ? row_num_literal(order_by) : Arel::Nodes::SqlLiteral.new("*")
27
+ x.projections = [p]
28
+ select_count = true
25
29
  else
26
- sql = o.cores.map { |x| do_visit_select_core(x, a) }.join
30
+ # NOTE: this should really be added here and we should built the
31
+ # wrapping SQL but than #replace_limit_offset! assumes it does that
32
+ # ... MS-SQL adapter code seems to be 'hacked' by a lot of people
33
+ #x.projections << row_num_literal(order_by)
27
34
  end
35
+ do_visit_select_core x, a
36
+ end.join
37
+
38
+ #sql = "SELECT _t.* FROM (#{sql}) as _t WHERE #{get_offset_limit_clause(o)}"
39
+ select_order_by ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
40
+ replace_limit_offset!(sql, limit_for(o.limit), o.offset && o.offset.value.to_i, select_order_by)
41
+
42
+ sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if select_count
28
43
 
29
- order ||= "ORDER BY #{@connection.determine_order_clause(sql)}"
30
- replace_limit_offset!(sql, limit_for(o.limit).to_i, o.offset && o.offset.value.to_i, order)
31
- sql = "SELECT COUNT(*) AS count_id FROM (#{sql}) AS subquery" if subquery
32
- else
33
- sql = super
34
- end
35
44
  add_lock!(sql, :lock => o.lock && true)
45
+
36
46
  sql
37
47
  end
38
-
39
- # MS-SQL doesn't support "SELECT...FOR UPDATE". Instead, it needs
40
- # WITH(ROWLOCK,UPDLOCK) specified after each table in the FROM clause.
41
- #
42
- # So, we return nothing here and add the appropriate stuff using add_lock! above.
43
- def visit_Arel_Nodes_Lock o
44
- # visit o.expr
45
- end
46
-
47
- def visit_Arel_Nodes_UpdateStatement o
48
+
49
+ def visit_Arel_Nodes_UpdateStatement(*args) # [o] AR <= 4.0 [o, a] on 4.1
50
+ o = args.first
48
51
  if o.orders.any? && o.limit.nil?
49
52
  o.limit = Nodes::Limit.new(9223372036854775807)
50
53
  end
51
54
  super
52
55
  end
53
-
54
- def visit_Arel_Nodes_Limit(o)
55
- "TOP (#{visit o.expr})"
56
+
57
+ def visit_Arel_Nodes_Lock o, a = nil
58
+ # MS-SQL doesn't support "SELECT...FOR UPDATE". Instead, it needs
59
+ # WITH(ROWLOCK,UPDLOCK) specified after each table in the FROM clause.
60
+ #
61
+ # we return nothing here and add the appropriate stuff with #add_lock!
62
+ #do_visit o.expr, a
56
63
  end
57
-
58
- def visit_Arel_Nodes_Ordering(o)
64
+
65
+ def visit_Arel_Nodes_Top o, a = nil
66
+ # `top` wouldn't really work here:
67
+ # User.select("distinct first_name").limit(10)
68
+ # would generate "select top 10 distinct first_name from users",
69
+ # which is invalid should be "select distinct top 10 first_name ..."
70
+ ""
71
+ end
72
+
73
+ def visit_Arel_Nodes_Limit o, a = nil
74
+ "TOP (#{do_visit o.expr, a})"
75
+ end
76
+
77
+ def visit_Arel_Nodes_Ordering o, a = nil
78
+ expr = do_visit o.expr, a
59
79
  if o.respond_to?(:direction)
60
- "#{visit o.expr} #{o.ascending? ? 'ASC' : 'DESC'}"
80
+ "#{expr} #{o.ascending? ? 'ASC' : 'DESC'}"
61
81
  else
62
- visit o.expr
82
+ expr
63
83
  end
64
84
  end
65
-
66
- def visit_Arel_Nodes_Bin(o)
67
- "#{visit o.expr} COLLATE Latin1_General_CS_AS_WS"
85
+
86
+ def visit_Arel_Nodes_Bin o, a = nil
87
+ "#{do_visit o.expr, a} COLLATE Latin1_General_CS_AS_WS"
68
88
  end
69
-
89
+
70
90
  private
71
-
72
- def select_count? o
73
- sel = o.cores.length == 1 && o.cores.first
74
- projections = sel && sel.projections.length == 1 && sel.projections
75
- projections && Arel::Nodes::Count === projections.first
91
+
92
+ def select_count? x
93
+ x.projections.length == 1 && Arel::Nodes::Count === x.projections.first
76
94
  end
77
-
78
- if instance_method('visit_Arel_Nodes_SelectCore').arity == 1
79
- def do_visit_select_core(x, a) # a = nil
80
- visit_Arel_Nodes_SelectCore(x)
95
+
96
+ def determine_order_by x, a
97
+ unless x.groups.empty?
98
+ "ORDER BY #{x.groups.map { |g| do_visit g, a }.join(', ')}"
99
+ else
100
+ table_pk = find_left_table_pk(x.froms, a)
101
+ table_pk == 'NULL' ? nil : "ORDER BY #{table_pk}"
81
102
  end
82
- else # > AREL 4.0
83
- def do_visit_select_core(x, a)
84
- visit_Arel_Nodes_SelectCore(x, a)
85
- end
86
103
  end
87
-
88
- include ArJdbc::MSSQL::LockHelpers::SqlServerAddLock
89
-
104
+
105
+ def row_num_literal order_by
106
+ Arel::Nodes::SqlLiteral.new("ROW_NUMBER() OVER (#{order_by}) as _row_num")
107
+ end
108
+
109
+ # @fixme raise exception of there is no pk?
110
+ # @fixme Table.primary_key will be deprecated. What is the replacement?
111
+ def find_left_table_pk o, a
112
+ return do_visit o.primary_key, a if o.instance_of? Arel::Table
113
+ find_left_table_pk o.left, a if o.kind_of? Arel::Nodes::Join
114
+ end
115
+
116
+ include ArJdbc::MSSQL::LockMethods
117
+
90
118
  include ArJdbc::MSSQL::LimitHelpers::SqlServerReplaceLimitOffset
91
-
119
+
92
120
  end
93
121
 
94
122
  class SQLServer2000 < SQLServer
data/lib/arjdbc.rb CHANGED
@@ -11,7 +11,7 @@ if defined?(JRUBY_VERSION)
11
11
  require 'active_record'
12
12
  end
13
13
  rescue LoadError => e
14
- warn "activerecord-jdbc-adapter requires ActiveRecord at runtime"
14
+ warn "activerecord-jdbc-adapter requires the activerecord gem at runtime"
15
15
  raise e
16
16
  end
17
17
  require 'arjdbc/jdbc'
@@ -1,18 +1,21 @@
1
1
  ArJdbc.load_java_part :DB2
2
2
 
3
+ require 'arjdbc/db2/column'
4
+
3
5
  module ArJdbc
6
+ # @note This adapter doesn't support explain `config.active_record.auto_explain_threshold_in_seconds` should be commented (Rails < 4.0)
4
7
  module DB2
5
8
 
6
- # This adapter doesn't support explain
7
- # config.active_record.auto_explain_threshold_in_seconds should be commented before rails 4.0
8
-
9
+ # @private
9
10
  def self.extended(adapter); initialize!; end
10
-
11
+
12
+ # @private
11
13
  @@_initialized = nil
12
-
14
+
15
+ # @private
13
16
  def self.initialize!
14
17
  return if @@_initialized; @@_initialized = true
15
-
18
+
16
19
  require 'arjdbc/jdbc/serialized_attributes_helper'
17
20
  ActiveRecord::Base.class_eval do
18
21
  def after_save_with_db2_lob
@@ -21,189 +24,105 @@ module ArJdbc
21
24
  value = ::ArJdbc::SerializedAttributesHelper.dump_column_value(self, column)
22
25
  next if value.nil? # already set NULL
23
26
 
24
- self.class.connection.write_large_object(
25
- column.type == :binary, column.name,
26
- self.class.table_name,
27
- self.class.primary_key,
28
- self.class.connection.quote(id), value
29
- )
27
+ self.class.connection.update_lob_value(self, column, value)
30
28
  end
31
29
  end
32
30
  end
33
31
  ActiveRecord::Base.after_save :after_save_with_db2_lob
34
32
  end
35
-
36
- def self.column_selector
37
- [ /(db2|zos)/i, lambda { |cfg, column| column.extend(::ArJdbc::DB2::Column) } ]
38
- end
39
33
 
34
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
40
35
  def self.jdbc_connection_class
41
36
  ::ActiveRecord::ConnectionAdapters::DB2JdbcConnection
42
37
  end
43
38
 
39
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
40
+ def jdbc_column_class
41
+ ::ActiveRecord::ConnectionAdapters::DB2Column
42
+ end
43
+
44
+ # @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
45
+ def self.arel_visitor_type(config = nil)
46
+ require 'arel/visitors/db2'; ::Arel::Visitors::DB2
47
+ end
48
+
49
+ # @deprecated no longer used
50
+ # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#arel2_visitors
44
51
  def self.arel2_visitors(config)
45
- require 'arel/visitors/db2'
46
- { 'db2' => ::Arel::Visitors::DB2 }
52
+ { 'db2' => arel_visitor_type }
47
53
  end
48
-
54
+
55
+ # @private
49
56
  def self.handle_lobs?; true; end
50
-
57
+
58
+ # @private
59
+ @@emulate_booleans = true
60
+
61
+ # Boolean emulation can be disabled using :
62
+ #
63
+ # ArJdbc::DB2.emulate_booleans = false
64
+ #
65
+ def self.emulate_booleans; @@emulate_booleans; end
66
+ def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
67
+
51
68
  def configure_connection
52
69
  schema = self.schema
53
70
  set_schema(schema) if schema && schema != config[:username]
54
71
  end
55
-
72
+
56
73
  ADAPTER_NAME = 'DB2'.freeze
57
-
74
+
58
75
  def adapter_name
59
76
  ADAPTER_NAME
60
77
  end
61
-
78
+
62
79
  NATIVE_DATABASE_TYPES = {
63
- :double => { :name => "double" },
64
- :bigint => { :name => "bigint" },
65
80
  :string => { :name => "varchar", :limit => 255 },
81
+ :integer => { :name => "integer" },
82
+ :float => { :name => "real" }, # :limit => 24
83
+ :double => { :name => "double" }, # :limit => 53
66
84
  :text => { :name => "clob" },
67
- :date => { :name => "date" },
68
85
  :binary => { :name => "blob" },
69
- :boolean => { :name => "smallint" }, # no native boolean type
70
86
  :xml => { :name => "xml" },
71
- :decimal => { :name => "decimal" },
72
- :char => { :name => "char" },
73
- :decfloat => { :name => "decfloat" },
74
- :rowid => { :name => "rowid" }, # rowid is a supported datatype on z/OS and i/5
75
- :serial => { :name => "serial" }, # supported datatype on Informix Dynamic Server
76
- :graphic => { :name => "graphic", :limit => 1 },
77
- :vargraphic => { :name => "vargraphic", :limit => 1 },
87
+ :decimal => { :name => "decimal" }, # :limit => 31
88
+ :char => { :name => "char" }, # :limit => 254
89
+ :date => { :name => "date" },
78
90
  :datetime => { :name => "timestamp" },
79
91
  :timestamp => { :name => "timestamp" },
80
- :time => { :name => "time" }
92
+ :time => { :name => "time" },
93
+ :boolean => { :name => "smallint" }, # no native boolean type
94
+ #:rowid => { :name => "rowid" }, # rowid is a supported datatype on z/OS and i/5
95
+ #:serial => { :name => "serial" }, # supported datatype on Informix Dynamic Server
96
+ #:graphic => { :name => "graphic", :limit => 1 }, # :limit => 127
81
97
  }
82
98
 
99
+ # @override
83
100
  def native_database_types
84
- super.merge(NATIVE_DATABASE_TYPES)
101
+ # NOTE: currently merging with what JDBC gives us since there's a lot
102
+ # of DB2-like stuff we could be connecting e.g. "classic", Z/OS etc.
103
+ # types = super
104
+ types = super.merge(NATIVE_DATABASE_TYPES)
105
+ types
85
106
  end
86
107
 
87
- @@emulate_booleans = true
88
-
89
- # Boolean emulation can be disabled using :
90
- #
91
- # ArJdbc::DB2.emulate_booleans = false
92
- #
93
- def self.emulate_booleans; @@emulate_booleans; end
94
- def self.emulate_booleans=(emulate); @@emulate_booleans = emulate; end
95
-
96
- module Column
97
-
98
- def type_cast(value)
99
- return nil if value.nil? || value == 'NULL' || value =~ /^\s*NULL\s*$/i
100
- case type
101
- when :string then value
102
- when :integer then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
103
- when :primary_key then value.respond_to?(:to_i) ? value.to_i : (value ? 1 : 0)
104
- when :float then value.to_f
105
- when :datetime then Column.cast_to_date_or_time(value)
106
- when :date then Column.cast_to_date_or_time(value)
107
- when :timestamp then Column.cast_to_time(value)
108
- when :time then Column.cast_to_time(value)
109
- # TODO AS400 stores binary strings in EBCDIC (CCSID 65535), need to convert back to ASCII
110
- else
111
- super
112
- end
113
- end
114
-
115
- def type_cast_code(var_name)
116
- case type
117
- when :datetime then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
118
- when :date then "ArJdbc::DB2::Column.cast_to_date_or_time(#{var_name})"
119
- when :timestamp then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
120
- when :time then "ArJdbc::DB2::Column.cast_to_time(#{var_name})"
121
- else
122
- super
123
- end
124
- end
125
-
126
- def self.cast_to_date_or_time(value)
127
- return value if value.is_a? Date
128
- return nil if value.blank?
129
- # https://github.com/jruby/activerecord-jdbc-adapter/commit/c225126e025df2e98ba3386c67e2a5bc5e5a73e6
130
- return Time.now if value =~ /^CURRENT/
131
- guess_date_or_time((value.is_a? Time) ? value : cast_to_time(value))
132
- rescue
133
- value
134
- end
135
-
136
- def self.cast_to_time(value)
137
- return value if value.is_a? Time
138
- # AS400 returns a 2 digit year, LUW returns a 4 digit year, so comp = true to help out AS400
139
- time = DateTime.parse(value).to_time rescue nil
140
- return nil unless time
141
- time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
142
- time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
143
- Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
144
- end
145
-
146
- def self.guess_date_or_time(value)
147
- return value if value.is_a? Date
148
- ( value && value.hour == 0 && value.min == 0 && value.sec == 0 ) ?
149
- Date.new(value.year, value.month, value.day) : value
150
- end
151
-
152
- private
153
- # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.html
154
- def simplified_type(field_type)
155
- case field_type
156
- when /^decimal\(1\)$/i then DB2.emulate_booleans ? :boolean : :integer
157
- when /smallint/i then DB2.emulate_booleans ? :boolean : :integer
158
- when /boolean/i then :boolean
159
- when /^real|double/i then :float
160
- when /int|serial/i then :integer
161
- # if a numeric column has no scale, lets treat it as an integer.
162
- # The AS400 rpg guys do this ALOT since they have no integer datatype ...
163
- when /decimal|numeric|decfloat/i
164
- extract_scale(field_type) == 0 ? :integer : :decimal
165
- when /timestamp/i then :timestamp
166
- when /datetime/i then :datetime
167
- when /time/i then :time
168
- when /date/i then :date
169
- when /clob|text/i then :text
170
- when /blob|binary/i then :binary
171
- when /for bit data/i then :binary
172
- when /xml/i then :xml
173
- when /^vargraphic/i then :vargraphic
174
- when /^graphic/i then :graphic
175
- when /rowid/i then :rowid # rowid is a supported datatype on z/OS and i/5
176
- else
177
- super
178
- end
179
- end
180
-
181
- # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
182
- def default_value(value)
183
- # IBM i (AS400) will return an empty string instead of null for no default
184
- return nil if value.blank?
185
-
186
- # string defaults are surrounded by single quotes
187
- return $1 if value =~ /^'(.*)'$/
188
-
189
- value
190
- end
191
- end
108
+ # @private
109
+ class TableDefinition < ::ActiveRecord::ConnectionAdapters::TableDefinition
192
110
 
193
- class TableDefinition < ::ActiveRecord::ConnectionAdapters::TableDefinition # :nodoc:
194
-
195
111
  def xml(*args)
196
112
  options = args.extract_options!
197
113
  column(args[0], 'xml', options)
198
114
  end
199
-
115
+
200
116
  # IBM DB adapter (MRI) compatibility :
201
-
117
+
118
+ # @private
119
+ # @deprecated
202
120
  def double(*args)
203
121
  options = args.extract_options!
204
122
  column(args[0], 'double', options)
205
123
  end
206
124
 
125
+ # @private
207
126
  def decfloat(*args)
208
127
  options = args.extract_options!
209
128
  column(args[0], 'decfloat', options)
@@ -214,28 +133,32 @@ module ArJdbc
214
133
  column(args[0], 'graphic', options)
215
134
  end
216
135
 
136
+ # @private
137
+ # @deprecated
217
138
  def vargraphic(*args)
218
139
  options = args.extract_options!
219
140
  column(args[0], 'vargraphic', options)
220
141
  end
221
142
 
143
+ # @private
144
+ # @deprecated
222
145
  def bigint(*args)
223
146
  options = args.extract_options!
224
147
  column(args[0], 'bigint', options)
225
148
  end
226
-
149
+
227
150
  def char(*args)
228
151
  options = args.extract_options!
229
152
  column(args[0], 'char', options)
230
153
  end
231
154
  # alias_method :character, :char
232
-
155
+
233
156
  end
234
157
 
235
158
  def table_definition(*args)
236
159
  new_table_definition(TableDefinition, *args)
237
160
  end
238
-
161
+
239
162
  def prefetch_primary_key?(table_name = nil)
240
163
  # TRUE if the table has no identity column
241
164
  names = table_name.upcase.split(".")
@@ -248,22 +171,16 @@ module ArJdbc
248
171
  def next_sequence_value(sequence_name)
249
172
  select_value("SELECT NEXT VALUE FOR #{sequence_name} FROM sysibm.sysdummy1")
250
173
  end
251
-
252
- def last_insert_id(sql)
253
- table_name = sql.split(/\s/)[2]
254
- result = select(ActiveRecord::Base.send(:sanitize_sql, %[SELECT IDENTITY_VAL_LOCAL() AS last_insert_id FROM #{table_name}], nil))
255
- result.last['last_insert_id']
256
- end
257
-
258
- def create_table(name, options = {}) #:nodoc:
174
+
175
+ def create_table(name, options = {})
259
176
  if zos?
260
177
  zos_create_table(name, options)
261
178
  else
262
179
  super(name, options)
263
180
  end
264
181
  end
265
-
266
- def zos_create_table(name, options = {}) # :nodoc:
182
+
183
+ def zos_create_table(name, options = {})
267
184
  # NOTE: this won't work for 4.0 - need to pass different initialize args :
268
185
  table_definition = TableDefinition.new(self)
269
186
  unless options[:id] == false
@@ -326,10 +243,12 @@ module ArJdbc
326
243
  end
327
244
 
328
245
  # Properly quotes the various data types.
329
- # +value+ contains the data, +column+ is optional and contains info on the field
330
- def quote(value, column = nil) # :nodoc:
246
+ # @param value contains the data
247
+ # @param column (optional) contains info on the field
248
+ # @override
249
+ def quote(value, column = nil)
331
250
  return value.quoted_id if value.respond_to?(:quoted_id)
332
-
251
+
333
252
  if column
334
253
  if column.respond_to?(:primary) && column.primary && column.klass != String
335
254
  return value.to_i.to_s
@@ -338,9 +257,9 @@ module ArJdbc
338
257
  return value.to_s
339
258
  end
340
259
  end
341
-
260
+
342
261
  column_type = column && column.type.to_sym
343
-
262
+
344
263
  case value
345
264
  when nil then "NULL"
346
265
  when Numeric # IBM_DB doesn't accept quotes on numeric types
@@ -371,8 +290,8 @@ module ArJdbc
371
290
  when Symbol then "'#{quote_string(value.to_s)}'"
372
291
  when Time
373
292
  # AS400 doesn't support date in time column
374
- if column && column_type == :time
375
- "'#{value.strftime("%H:%M:%S")}'"
293
+ if column_type == :time
294
+ quote_time(value)
376
295
  else
377
296
  super
378
297
  end
@@ -380,10 +299,27 @@ module ArJdbc
380
299
  end
381
300
  end
382
301
 
302
+ # @override
303
+ def quoted_date(value)
304
+ if value.acts_like?(:time) && value.respond_to?(:usec)
305
+ usec = sprintf("%06d", value.usec)
306
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
307
+ "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
308
+ else
309
+ super
310
+ end
311
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
312
+
313
+ def quote_time(value)
314
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
315
+ # AS400 doesn't support date in time column
316
+ "'#{value.strftime("%H:%M:%S")}'"
317
+ end
318
+
383
319
  def quote_column_name(column_name)
384
320
  column_name.to_s
385
321
  end
386
-
322
+
387
323
  def modify_types(types)
388
324
  super(types)
389
325
  types[:primary_key] = 'int not null generated by default as identity (start with 1) primary key'
@@ -398,12 +334,8 @@ module ArJdbc
398
334
  super(type, limit, precision, scale)
399
335
  end
400
336
 
401
- def add_limit_offset!(sql, options)
402
- replace_limit_offset!(sql, options[:limit], options[:offset])
403
- end
404
-
405
- def add_column_options!(sql, options) # :nodoc:
406
- # handle case of defaults for CLOB columns,
337
+ def add_column_options!(sql, options)
338
+ # handle case of defaults for CLOB columns,
407
339
  # which might get incorrect if we write LOBs in the after_save callback
408
340
  if options_include_default?(options)
409
341
  column = options[:column]
@@ -413,7 +345,7 @@ module ArJdbc
413
345
  if column && column.type == :binary
414
346
  # quoting required for the default value of a column :
415
347
  value = options.delete(:default)
416
- # DB2 z/OS only allows NULL or "" (empty) string as DEFAULT value
348
+ # DB2 z/OS only allows NULL or "" (empty) string as DEFAULT value
417
349
  # for a BLOB column. non-empty string and non-NULL, return error!
418
350
  if value.nil?
419
351
  sql_value = "NULL"
@@ -425,25 +357,31 @@ module ArJdbc
425
357
  end
426
358
  super
427
359
  end
428
-
360
+
361
+ # @note Only used with (non-AREL) ActiveRecord **2.3**.
362
+ # @see Arel::Visitors::DB2
363
+ def add_limit_offset!(sql, options)
364
+ replace_limit_offset!(sql, options[:limit], options[:offset])
365
+ end if ::ActiveRecord::VERSION::MAJOR < 3
366
+
367
+ # @private shared with {Arel::Visitors::DB2}
429
368
  def replace_limit_offset!(sql, limit, offset)
430
- if limit
431
- limit = limit.to_i
369
+ return sql unless limit
432
370
 
433
- if !offset
434
- if limit == 1
435
- sql << " FETCH FIRST ROW ONLY"
436
- else
437
- sql << " FETCH FIRST #{limit} ROWS ONLY"
438
- end
371
+ limit = limit.to_i
372
+ if offset
373
+ replace_limit_offset_with_ordering(sql, limit, offset)
374
+ else
375
+ if limit == 1
376
+ sql << " FETCH FIRST ROW ONLY"
439
377
  else
440
- replace_limit_offset_with_ordering( sql, limit, offset )
378
+ sql << " FETCH FIRST #{limit} ROWS ONLY"
441
379
  end
442
-
380
+ sql
443
381
  end
444
- sql
445
382
  end
446
383
 
384
+ # @private only used from {Arel::Visitors::DB2}
447
385
  def replace_limit_offset_for_arel!( query, sql )
448
386
  replace_limit_offset_with_ordering sql, query.limit.value, query.offset && query.offset.value, query.orders
449
387
  end
@@ -454,12 +392,12 @@ module ArJdbc
454
392
  sql
455
393
  end
456
394
  private :replace_limit_offset_with_ordering
457
-
395
+
458
396
  def build_ordering( orders )
459
397
  return '' unless orders.size > 0
460
398
  # need to remove the library/table names from the orderings because we are not really ordering by them anymore
461
399
  # we are actually ordering by the results of a query where the result set has the same column names
462
- orders = orders.map do |o|
400
+ orders = orders.map do |o|
463
401
  # need to keep in mind that the order clause could be wrapped in a function
464
402
  matches = /(?:\w+\(|\s)*(\S+)(?:\)|\s)*/.match(o)
465
403
  o = o.gsub( matches[1], matches[1].split('.').last ) if matches
@@ -483,13 +421,14 @@ module ArJdbc
483
421
  statement << ' UNIQUE ' if options[:unique]
484
422
  statement << " INDEX #{ActiveRecord::Base.table_name_prefix}#{options[:name]} "
485
423
  statement << " ON #{table_name}(#{column_name})"
486
-
424
+
487
425
  execute statement
488
426
  end
489
427
  end
490
428
 
491
- def remove_index(table_name, options = { })
492
- execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
429
+ # @override
430
+ def remove_index!(table_name, index_name)
431
+ execute "DROP INDEX #{quote_column_name(index_name)}"
493
432
  end
494
433
 
495
434
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020130.html
@@ -537,9 +476,9 @@ module ArJdbc
537
476
  change_column_null(table_name, column_name, options[:null])
538
477
  end
539
478
  end
540
-
541
- # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
542
- def remove_column(table_name, *column_names) # :nodoc:
479
+
480
+ def remove_column(table_name, *column_names)
481
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.dbobj.doc/doc/t0020132.html
543
482
  outcome = nil
544
483
  column_names = column_names.flatten
545
484
  for column_name in column_names
@@ -549,18 +488,19 @@ module ArJdbc
549
488
  column_names.size == 1 ? outcome : nil
550
489
  end
551
490
 
552
- # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
553
- def rename_table(name, new_name) # :nodoc:
491
+ def rename_table(name, new_name)
492
+ # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000980.html
554
493
  execute_table_change("RENAME TABLE #{name} TO #{new_name}", new_name, 'Rename Table')
555
494
  end
556
-
495
+
557
496
  def tables
558
497
  @connection.tables(nil, schema)
559
498
  end
560
499
 
561
500
  # only record precision and scale for types that can set them via CREATE TABLE:
562
501
  # http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0000927.html
563
- HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) #TIMESTAMP
502
+
503
+ HAVE_LIMIT = %w(FLOAT DECFLOAT CHAR VARCHAR CLOB BLOB NCHAR NCLOB DBCLOB GRAPHIC VARGRAPHIC) # TIMESTAMP
564
504
  HAVE_PRECISION = %w(DECIMAL NUMERIC)
565
505
  HAVE_SCALE = %w(DECIMAL NUMERIC)
566
506
 
@@ -590,49 +530,68 @@ module ArJdbc
590
530
  def recreate_database(name = nil, options = {})
591
531
  drop_database(name)
592
532
  end
593
-
533
+
594
534
  def drop_database(name = nil)
595
535
  tables.each { |table| drop_table("#{table}") }
596
536
  end
597
-
537
+
598
538
  def execute_table_change(sql, table_name, name = nil)
599
539
  outcome = execute(sql, name)
600
540
  reorg_table(table_name, name)
601
541
  outcome
602
542
  end
603
543
  protected :execute_table_change
604
-
544
+
605
545
  def reorg_table(table_name, name = nil)
606
546
  exec_update "call sysproc.admin_cmd ('REORG TABLE #{table_name}')", name, []
607
547
  end
608
548
  private :reorg_table
609
-
549
+
610
550
  # alias_method :execute_and_auto_confirm, :execute
611
551
 
552
+ # Returns the value of an identity column of the last *INSERT* statement
553
+ # made over this connection.
554
+ # @note Check the *IDENTITY_VAL_LOCAL* function for documentation.
555
+ # @return [Fixnum]
556
+ def last_insert_id
557
+ @connection.identity_val_local
558
+ end
559
+
560
+ # NOTE: only setup query analysis on AR <= 3.0 since on 3.1 {#exec_query},
561
+ # {#exec_insert} will be used for AR generated queries/inserts etc.
562
+ # Also there's prepared statement support and {#execute} is meant to stay
563
+ # as a way of running non-prepared SQL statements (returning raw results).
564
+ if ActiveRecord::VERSION::MAJOR < 3 ||
565
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
566
+
612
567
  def _execute(sql, name = nil)
613
568
  if self.class.select?(sql)
614
569
  @connection.execute_query_raw(sql)
615
570
  elsif self.class.insert?(sql)
616
- (@connection.execute_insert(sql) || last_insert_id(sql)).to_i
571
+ @connection.execute_insert(sql) || last_insert_id
617
572
  else
618
573
  @connection.execute_update(sql)
619
574
  end
620
575
  end
621
576
  private :_execute
622
-
577
+
578
+ end
579
+
623
580
  DRIVER_NAME = 'com.ibm.db2.jcc.DB2Driver'.freeze
624
-
581
+
582
+ # @private
625
583
  def zos?
626
584
  @zos = nil unless defined? @zos
627
585
  return @zos unless @zos.nil?
628
- @zos =
586
+ @zos =
629
587
  if url = config[:url]
630
588
  !!( url =~ /^jdbc:db2j:net:/ && config[:driver] == DRIVER_NAME )
631
589
  else
632
590
  nil
633
591
  end
634
592
  end
635
-
593
+
594
+ # @private
636
595
  # @deprecated no longer used
637
596
  def as400?
638
597
  false
@@ -641,21 +600,21 @@ module ArJdbc
641
600
  def schema
642
601
  db2_schema
643
602
  end
644
-
603
+
645
604
  def schema=(schema)
646
605
  set_schema(@db2_schema = schema) if db2_schema != schema
647
606
  end
648
-
607
+
649
608
  private
650
-
609
+
651
610
  def set_schema(schema)
652
611
  execute("SET SCHEMA #{schema}")
653
612
  end
654
-
613
+
655
614
  def db2_schema
656
615
  @db2_schema = false unless defined? @db2_schema
657
616
  return @db2_schema if @db2_schema != false
658
- @db2_schema =
617
+ @db2_schema =
659
618
  if config[:schema].present?
660
619
  config[:schema]
661
620
  elsif config[:jndi].present?
@@ -665,6 +624,16 @@ module ArJdbc
665
624
  config[:username].presence || ENV['USER']
666
625
  end
667
626
  end
668
-
627
+
669
628
  end
670
629
  end
630
+
631
+ module ActiveRecord::ConnectionAdapters
632
+
633
+ remove_const(:DB2Column) if const_defined?(:DB2Column)
634
+
635
+ class DB2Column < JdbcColumn
636
+ include ::ArJdbc::DB2::Column
637
+ end
638
+
639
+ end