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
@@ -4,13 +4,15 @@ require 'arjdbc/hsqldb/explain_support'
4
4
  module ArJdbc
5
5
  module HSQLDB
6
6
  include ExplainSupport
7
-
7
+
8
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn#column_types
8
9
  def self.column_selector
9
- [ /hsqldb/i, lambda { |cfg, column| column.extend(::ArJdbc::HSQLDB::Column) } ]
10
+ [ /hsqldb/i, lambda { |config, column| column.extend(Column) } ]
10
11
  end
11
12
 
13
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
12
14
  module Column
13
-
15
+
14
16
  private
15
17
 
16
18
  def extract_limit(sql_type)
@@ -21,7 +23,7 @@ module ArJdbc
21
23
  when /^bigint/i then @sql_type = 'bigint'; limit = 8
22
24
  when /^double/i then @sql_type = 'double'; limit = 8
23
25
  when /^real/i then @sql_type = 'real'; limit = 8
24
- # NOTE: once again we get incorrect "limits" from HypesSQL's JDBC
26
+ # NOTE: once again we get incorrect "limits" from HypesSQL's JDBC
25
27
  # thus yet again we need to fix incorrectly detected limits :
26
28
  when /^integer/i then @sql_type = 'integer'; limit = 4
27
29
  when /^float/i then @sql_type = 'float'; limit = 8
@@ -31,79 +33,82 @@ module ArJdbc
31
33
  when /^time/i then @sql_type = 'time'; limit = nil
32
34
  when /^date/i then @sql_type = 'date'; limit = nil
33
35
  else
34
- # HSQLDB appears to return "LONGVARCHAR(0)" for :text columns,
36
+ # HSQLDB appears to return "LONGVARCHAR(0)" for :text columns,
35
37
  # which for AR purposes should be interpreted as "no limit" :
36
38
  limit = nil if sql_type =~ /\(0\)$/
37
39
  end
38
40
  limit
39
41
  end
40
-
42
+
41
43
  def simplified_type(field_type)
42
44
  case field_type
43
- when /longvarchar/i then :text
44
- when /int/i then :integer # TINYINT, SMALLINT, BIGINT, INT
45
- when /real|double/i then :float
46
- when /bit/i then :boolean
47
- when /binary/i then :binary # VARBINARY, LONGVARBINARY
45
+ when /^nvarchar/i then :string
46
+ when /^character/i then :string
47
+ when /^longvarchar/i then :text
48
+ when /int/i then :integer # TINYINT, SMALLINT, BIGINT, INT
49
+ when /real|double/i then :float
50
+ when /^bit/i then :boolean
51
+ when /binary/i then :binary # VARBINARY, LONGVARBINARY
48
52
  else
49
53
  super
50
54
  end
51
55
  end
52
-
56
+
53
57
  # Post process default value from JDBC into a Rails-friendly format (columns{-internal})
54
58
  def default_value(value)
55
59
  # JDBC returns column default strings with actual single quotes around the value.
56
60
  return $1 if value =~ /^'(.*)'$/
57
61
  value
58
62
  end
59
-
63
+
60
64
  end
61
65
 
62
- ADAPTER_NAME = 'HSQLDB' # :nodoc:
63
-
64
- def adapter_name # :nodoc:
65
- ADAPTER_NAME
66
+ # @see ActiveRecord::ConnectionAdapters::Jdbc::ArelSupport
67
+ def self.arel_visitor_type(config = nil)
68
+ require 'arel/visitors/hsqldb'; ::Arel::Visitors::HSQLDB
66
69
  end
67
70
 
68
- def self.arel2_visitors(config)
69
- require 'arel/visitors/hsqldb'
70
- {
71
- 'hsqldb' => ::Arel::Visitors::HSQLDB,
72
- 'jdbchsqldb' => ::Arel::Visitors::HSQLDB,
73
- }
71
+ ADAPTER_NAME = 'HSQLDB'.freeze
72
+
73
+ def adapter_name
74
+ ADAPTER_NAME
74
75
  end
75
-
76
+
76
77
  NATIVE_DATABASE_TYPES = {
77
78
  :primary_key => "integer GENERATED BY DEFAULT AS IDENTITY(START WITH 0) PRIMARY KEY",
78
- :string => { :name => "varchar", :limit => 255 },
79
+ :string => { :name => "varchar", :limit => 255 }, # :limit => 2147483647
79
80
  :text => { :name => "clob" },
80
81
  :binary => { :name => "blob" },
81
- :boolean => { :name => "boolean" },
82
+ :boolean => { :name => "boolean" }, # :name => "tinyint", :limit => 1
83
+ :bit => { :name=>"bit" }, # stored as 0/1 on HSQLDB 2.2 (translates true/false)
82
84
  :integer => { :name => "integer", :limit => 4 },
83
- :float => { :name => "float", :limit => 8 },
85
+ :decimal => { :name => "decimal" }, # :limit => 2147483647
86
+ :numeric => { :name => "numeric" }, # :limit => 2147483647
84
87
  # NOTE: fix incorrectly detected limits :
85
88
  :tinyint => { :name => "tinyint", :limit => 1 },
86
89
  :smallint => { :name => "smallint", :limit => 2 },
87
90
  :bigint => { :name => "bigint", :limit => 8 },
91
+ :float => { :name => "float" },
88
92
  :double => { :name => "double", :limit => 8 },
89
93
  :real => { :name => "real", :limit => 8 },
94
+ :date => { :name=>"date" },
95
+ :time => { :name=>"time" },
96
+ :timestamp => { :name=>"timestamp" },
97
+ :datetime => { :name=>"timestamp" },
98
+ :other => { :name=>"other" },
99
+ # NOTE: would be great if AR allowed as to refactor as :
100
+ # t.column :string, :ignorecase => true
101
+ :character => { :name => "character" },
102
+ :varchar_ignorecase => { :name => "varchar_ignorecase" },
90
103
  }
91
-
104
+
105
+ # @override
92
106
  def native_database_types
93
- super.merge NATIVE_DATABASE_TYPES
94
- end
95
-
96
- def modify_types(types)
97
- super(types)
98
- types[:primary_key] = NATIVE_DATABASE_TYPES[:primary_key]
99
- types[:string] = NATIVE_DATABASE_TYPES[:string].dup
100
- #types[:integer][:limit] = nil
101
- #types[:boolean][:limit] = nil
102
- types[:text][:limit] = nil
103
- types
107
+ NATIVE_DATABASE_TYPES
104
108
  end
105
109
 
106
- def quote(value, column = nil) # :nodoc:
110
+ # @override
111
+ def quote(value, column = nil)
107
112
  return value.quoted_id if value.respond_to?(:quoted_id)
108
113
 
109
114
  case value
@@ -118,8 +123,12 @@ module ArJdbc
118
123
  "'#{quote_string(value)}'"
119
124
  end
120
125
  when Time
121
- if column && column.type == :time
126
+ column_type = column && column.type
127
+ if column_type == :time
122
128
  "'#{value.strftime("%H:%M:%S")}'"
129
+ #elsif column_type == :timestamp # || column_type == :datetime
130
+ #value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
131
+ #"'#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{sprintf("%06d", value.usec)}'"
123
132
  else
124
133
  super
125
134
  end
@@ -128,7 +137,21 @@ module ArJdbc
128
137
  end
129
138
  end
130
139
 
131
- def quote_column_name(name) # :nodoc:
140
+ # Quote date/time values for use in SQL input.
141
+ # Includes microseconds if the value is a Time responding to usec.
142
+ # @override
143
+ def quoted_date(value)
144
+ if value.acts_like?(:time) && value.respond_to?(:usec)
145
+ usec = sprintf("%06d", value.usec)
146
+ value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
147
+ "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
148
+ else
149
+ super
150
+ end
151
+ end if ::ActiveRecord::VERSION::MAJOR >= 3
152
+
153
+ # @override
154
+ def quote_column_name(name)
132
155
  name = name.to_s
133
156
  if name =~ /[-]/
134
157
  %Q{"#{name.upcase}"}
@@ -137,13 +160,15 @@ module ArJdbc
137
160
  end
138
161
  end
139
162
 
163
+ # @override
140
164
  def add_column(table_name, column_name, type, options = {})
141
165
  add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
142
166
  add_column_options!(add_column_sql, options)
143
167
  execute(add_column_sql)
144
168
  end
145
169
 
146
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
170
+ # @override
171
+ def change_column(table_name, column_name, type, options = {})
147
172
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} #{type_to_sql(type, options[:limit])}"
148
173
  end
149
174
 
@@ -151,17 +176,18 @@ module ArJdbc
151
176
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET DEFAULT #{quote(default)}"
152
177
  end
153
178
 
179
+ # @override
154
180
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
155
181
  execute "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} RENAME TO #{new_column_name}"
156
182
  end
157
183
 
158
- # Maps logical Rails types to MySQL-specific data types.
184
+ # @override
159
185
  def type_to_sql(type, limit = nil, precision = nil, scale = nil)
160
186
  return super if defined?(::Jdbc::H2) || type.to_s != 'integer' || limit == nil
161
-
162
187
  type
163
188
  end
164
189
 
190
+ # @override
165
191
  def rename_table(name, new_name)
166
192
  execute "ALTER TABLE #{name} RENAME TO #{new_name}"
167
193
  end
@@ -171,46 +197,47 @@ module ArJdbc
171
197
  Integer(identity.nil? ? 0 : identity)
172
198
  end
173
199
 
200
+ # @private
174
201
  def _execute(sql, name = nil)
175
202
  result = super
176
203
  self.class.insert?(sql) ? last_insert_id : result
177
204
  end
178
205
  private :_execute
179
206
 
180
- def add_limit_offset!(sql, options) #:nodoc:
207
+ # @note Only used with (non-AREL) ActiveRecord **2.3**.
208
+ # @see Arel::Visitors::HSQLDB#limit_offset
209
+ def add_limit_offset!(sql, options)
181
210
  if sql =~ /^select/i
182
211
  offset = options[:offset] || 0
183
- bef = sql[7..-1]
184
212
  if limit = options[:limit]
185
- sql.replace "SELECT LIMIT #{offset} #{limit} #{bef}"
213
+ sql.replace "SELECT LIMIT #{offset} #{limit} #{sql[7..-1]}"
186
214
  elsif offset > 0
187
- sql.replace "SELECT LIMIT #{offset} 0 #{bef}"
215
+ sql.replace "SELECT LIMIT #{offset} 0 #{sql[7..-1]}"
188
216
  end
189
217
  end
190
- end
218
+ end if ::ActiveRecord::VERSION::MAJOR < 3
191
219
 
220
+ # @override
192
221
  def empty_insert_statement_value
193
- # on HSQLDB only work with tables that have a default value for each
222
+ # on HSQLDB only work with tables that have a default value for each
194
223
  # and every column ... you'll need to avoid `Model.create!` on 4.0
195
224
  'DEFAULT VALUES'
196
225
  end
197
-
198
- # filter out system tables (that otherwise end up in db/schema.rb)
199
- # JdbcConnection#tables
200
- # now takes an optional block filter so we can screen out
201
- # rows corresponding to system tables. HSQLDB names its
202
- # system tables SYSTEM.*, but H2 seems to name them without
203
- # any kind of convention
226
+
227
+ # We filter out HSQLDB's system tables (named "SYSTEM.*").
228
+ # @override
204
229
  def tables
205
230
  @connection.tables.select { |row| row.to_s !~ /^system_/i }
206
231
  end
207
232
 
233
+ # @override
208
234
  def remove_index(table_name, options = {})
209
235
  execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
210
236
  end
211
-
237
+
238
+ # @override
212
239
  def structure_dump
213
- execute('SCRIPT').map do |result|
240
+ execute('SCRIPT').map do |result|
214
241
  # [ { 'command' => SQL }, { 'command' ... }, ... ]
215
242
  case sql = result.first[1] # ['command']
216
243
  when /CREATE USER SA PASSWORD DIGEST .*?/i then nil
@@ -221,24 +248,28 @@ module ArJdbc
221
248
  end.compact.join("\n\n")
222
249
  end
223
250
 
251
+ # @see #structure_dump
224
252
  def structure_load(dump)
225
253
  dump.each_line("\n\n") { |ddl| execute(ddl) }
226
254
  end
227
-
255
+
228
256
  def shutdown
229
257
  execute 'SHUTDOWN'
230
258
  end
231
-
232
- def recreate_database(name = nil, options = {}) # :nodoc:
259
+
260
+ # @private
261
+ def recreate_database(name = nil, options = {})
233
262
  drop_database(name)
234
263
  create_database(name, options)
235
264
  end
236
-
237
- def create_database(name = nil, options = {}); end # :nodoc:
238
-
239
- def drop_database(name = nil) # :nodoc:
265
+
266
+ # @private
267
+ def create_database(name = nil, options = {}); end
268
+
269
+ # @private
270
+ def drop_database(name = nil)
240
271
  execute('DROP SCHEMA PUBLIC CASCADE')
241
272
  end
242
-
273
+
243
274
  end
244
275
  end
@@ -8,59 +8,99 @@ require 'arjdbc/jdbc/connection_methods'
8
8
  require 'arjdbc/jdbc/driver'
9
9
  require 'arjdbc/jdbc/column'
10
10
  require 'arjdbc/jdbc/connection'
11
+ require 'arjdbc/jdbc/arel_support'
11
12
  require 'arjdbc/jdbc/callbacks'
12
13
  require 'arjdbc/jdbc/extension'
13
14
  require 'arjdbc/jdbc/type_converter'
14
15
 
15
16
  module ActiveRecord
16
17
  module ConnectionAdapters
18
+ # Built on top of `ActiveRecord::ConnectionAdapters::AbstractAdapter` which
19
+ # provides the abstract interface for database-specific functionality, this
20
+ # class serves 2 purposes in AR-JDBC :
21
+ # - as a base class for sub-classes
22
+ # - usable standalone (or with a mixed in adapter spec module)
23
+ #
24
+ # Historically this class is mostly been used standalone and that's still a
25
+ # valid use-case esp. since (with it's `arjdbc.jdbc.RubyJdbcConnectionClass`)
26
+ # JDBC provides a unified interface for all databases in Java it tries to do
27
+ # it's best implementing all `ActiveRecord` functionality on top of that.
28
+ # This might no be perfect that's why it checks for a `config[:adapter_spec]`
29
+ # module (or tries to resolve one from the JDBC driver's meta-data) and if
30
+ # the database has "extended" AR-JDBC support mixes in the given module for
31
+ # each adapter instance.
32
+ # This is sufficient for most database specific specs we support, but for
33
+ # compatibility with native (MRI) adapters it's perfectly fine to sub-class
34
+ # the adapter and override some of its API methods.
17
35
  class JdbcAdapter < AbstractAdapter
18
36
  extend ShadowCoreMethods
19
-
20
- include JdbcConnectionPoolCallbacks
21
-
37
+
38
+ include Jdbc::ArelSupport
39
+ include Jdbc::ConnectionPoolCallbacks
40
+
22
41
  attr_reader :config
23
-
24
- def initialize(connection, logger, config = nil) # (logger, config)
25
- if config.nil? && logger.respond_to?(:key?) # only 2 arguments given
42
+
43
+ # Initializes the (JDBC connection) adapter instance.
44
+ # The passed configuration Hash's keys are symbolized, thus changes to
45
+ # the original `config` keys won't be reflected in the adapter.
46
+ # If the adapter's sub-class or the spec module that this instance will
47
+ # extend in responds to `configure_connection` than it will be called.
48
+ # @param connection an (optional) connection instance
49
+ # @param logger the `ActiveRecord::Base.logger` to use (or nil)
50
+ # @param config the database configuration
51
+ # @note `initialize(logger, config)` with 2 arguments is supported as well
52
+ def initialize(connection, logger, config = nil)
53
+ if config.nil? && logger.respond_to?(:key?) # (logger, config)
26
54
  config, logger, connection = logger, connection, nil
27
55
  end
28
-
29
- @config = config
30
-
56
+
57
+ @config = config.respond_to?(:symbolize_keys) ? config.symbolize_keys : config
58
+ # NOTE: JDBC 4.0 drivers support checking if connection isValid
59
+ # thus no need to @config[:connection_alive_sql] ||= 'SELECT 1'
60
+ #
61
+ # NOTE: setup to retry 5-times previously - maybe do not set at all ?
62
+ @config[:retry_count] ||= 1
63
+
31
64
  @config[:adapter_spec] = adapter_spec(@config) unless @config.key?(:adapter_spec)
32
65
  spec = @config[:adapter_spec]
33
-
34
- connection ||= jdbc_connection_class(spec).new(@config)
35
-
36
- super(connection, logger)
37
-
66
+
38
67
  # kind of like `extend ArJdbc::MyDB if self.class == JdbcAdapter` :
39
68
  klass = @config[:adapter_class]
40
69
  extend spec if spec && ( ! klass || klass == JdbcAdapter)
41
-
42
- connection.adapter = self # prepares native database types
43
-
70
+ # NOTE: adapter spec's init_connection only called if instantiated here :
71
+ connection ||= jdbc_connection_class(spec).new(@config, self)
72
+
73
+ super(connection, logger)
74
+
44
75
  # NOTE: should not be necessary for JNDI due reconnect! on checkout :
45
76
  configure_connection if respond_to?(:configure_connection)
46
-
47
- JndiConnectionPoolCallbacks.prepare(self, connection)
48
-
49
- @visitor = new_visitor(@config) # nil if no AREL (AR-2.3)
77
+
78
+ Jdbc::JndiConnectionPoolCallbacks.prepare(self, connection)
79
+
80
+ @visitor = new_visitor # nil if no AREL (AR-2.3)
50
81
  end
51
-
82
+
83
+ # Returns the (JDBC) connection class to be used for this adapter.
84
+ # This is used by (database specific) spec modules to override the class
85
+ # used assuming some of the available methods have been re-defined.
86
+ # @see ActiveRecord::ConnectionAdapters::JdbcConnection
52
87
  def jdbc_connection_class(spec)
53
88
  connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
54
89
  connection_class ? connection_class : ::ActiveRecord::ConnectionAdapters::JdbcConnection
55
90
  end
56
91
 
92
+ # Returns the (JDBC) `ActiveRecord` column class for this adapter.
93
+ # This is used by (database specific) spec modules to override the class.
94
+ # @see ActiveRecord::ConnectionAdapters::JdbcColumn
57
95
  def jdbc_column_class
58
- ActiveRecord::ConnectionAdapters::JdbcColumn
96
+ ::ActiveRecord::ConnectionAdapters::JdbcColumn
59
97
  end
60
98
 
61
- # Retrieve the raw java.sql.Connection object.
62
- # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
63
- # connection should be made - to really return the native (SQL) object.
99
+ # Retrieve the raw `java.sql.Connection` object.
100
+ # The unwrap parameter is useful if an attempt to unwrap a pooled (JNDI)
101
+ # connection should be made - to really return the 'native' JDBC object.
102
+ # @param unwrap [true, false] whether to unwrap the connection object
103
+ # @return [Java::JavaSql::Connection] the JDBC connection
64
104
  def jdbc_connection(unwrap = nil)
65
105
  java_connection = raw_connection.connection
66
106
  return java_connection unless unwrap
@@ -75,7 +115,14 @@ module ActiveRecord
75
115
  end
76
116
  end
77
117
 
78
- # Locate specialized adapter specification if one exists based on config data
118
+ # Locate the specialized (database specific) adapter specification module
119
+ # if one exists based on provided configuration data. This module will than
120
+ # extend an instance of the adapter (unless an `:adapter_class` provided).
121
+ #
122
+ # This method is called during {#initialize} unless an explicit
123
+ # `config[:adapter_spec]` is set.
124
+ # @param config the configuration to check for `:adapter_spec`
125
+ # @return [Module] the database specific module
79
126
  def adapter_spec(config)
80
127
  dialect = (config[:dialect] || config[:driver]).to_s
81
128
  ::ArJdbc.modules.each do |constant| # e.g. ArJdbc::MySQL
@@ -87,7 +134,7 @@ module ActiveRecord
87
134
 
88
135
  if (config[:jndi] || config[:data_source]) && ! config[:dialect]
89
136
  begin
90
- data_source = config[:data_source] ||
137
+ data_source = config[:data_source] ||
91
138
  Java::JavaxNaming::InitialContext.new.lookup(config[:jndi])
92
139
  connection = data_source.getConnection
93
140
  config[:dialect] = connection.getMetaData.getDatabaseProductName
@@ -103,33 +150,40 @@ module ActiveRecord
103
150
  nil
104
151
  end
105
152
 
106
- def modify_types(types)
107
- types
153
+ ADAPTER_NAME = 'JDBC'.freeze
154
+
155
+ # @return [String] the 'JDBC' adapter name.
156
+ def adapter_name
157
+ ADAPTER_NAME
108
158
  end
109
159
 
110
- def adapter_name # :nodoc:
111
- 'JDBC'
160
+ # @override
161
+ # Will return true even when native adapter classes passed in
162
+ # e.g. `jdbc_adapter.is_a? ConnectionAdapter::PostgresqlAdapter`
163
+ #
164
+ # This is only necessary (for built-in adapters) when
165
+ # `config[:adapter_class]` is forced to `nil` and the `:adapter_spec`
166
+ # module is used to extend the `JdbcAdapter`, otherwise we replace the
167
+ # class constants for built-in adapters (MySQL, PostgreSQL and SQLite3).
168
+ def is_a?(klass)
169
+ # This is to fake out current_adapter? conditional logic in AR tests
170
+ if klass.is_a?(Class) && klass.name =~ /#{adapter_name}Adapter$/i
171
+ true
172
+ else
173
+ super
174
+ end
112
175
  end
113
176
 
177
+ # @deprecated re-implemented - no longer used
178
+ # @return [Hash] the AREL visitor to use
179
+ # If there's a `self.arel2_visitors(config)` method on the adapter
180
+ # spec than it is preferred and will be used instead of this one.
114
181
  def self.arel2_visitors(config)
115
182
  { 'jdbc' => ::Arel::Visitors::ToSql }
116
183
  end
117
184
 
118
- # NOTE: called from {ConnectionPool#checkout} (up till AR-3.2)
119
- def self.visitor_for(pool)
120
- config = pool.spec.config
121
- adapter = config[:adapter] # e.g. "sqlite3" (based on {#adapter_name})
122
- unless visitor = ::Arel::Visitors::VISITORS[ adapter ]
123
- adapter_spec = config[:adapter_spec] || self # e.g. ArJdbc::SQLite3
124
- if adapter =~ /^(jdbc|jndi)$/
125
- visitor = adapter_spec.arel2_visitors(config).values.first
126
- else
127
- visitor = adapter_spec.arel2_visitors(config)[adapter]
128
- end
129
- end
130
- ( prepared_statements?(config) ? visitor : bind_substitution(visitor) ).new(pool)
131
- end
132
-
185
+ # @deprecated re-implemented - no longer used
186
+ # @see #arel2_visitors
133
187
  def self.configure_arel2_visitors(config)
134
188
  visitors = ::Arel::Visitors::VISITORS
135
189
  klass = config[:adapter_spec]
@@ -144,83 +198,45 @@ module ActiveRecord
144
198
  visitor
145
199
  end
146
200
 
147
- def new_visitor(config = self.config)
148
- visitor = ::Arel::Visitors::VISITORS[ adapter = config[:adapter] ]
149
- unless visitor
150
- visitor = self.class.configure_arel2_visitors(config)
151
- unless visitor
152
- raise "no visitor configured for adapter: #{adapter.inspect}"
153
- end
154
- end
155
- ( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
156
- end
157
- protected :new_visitor
158
-
159
- unless defined? ::Arel::Visitors::VISITORS # NO-OP when no AREL (AR-2.3)
160
- def self.configure_arel2_visitors(config); end
161
- def new_visitor(config = self.config); end
162
- end
163
-
164
- @@bind_substitutions = nil
165
-
166
- # @return a {#Arel::Visitors::BindVisitor} class for given visitor type
167
- def self.bind_substitution(visitor)
168
- # NOTE: similar convention as in AR (but no base substitution type) :
169
- # class BindSubstitution < ::Arel::Visitors::ToSql
170
- # include ::Arel::Visitors::BindVisitor
171
- # end
172
- return const_get(:BindSubstitution) if const_defined?(:BindSubstitution)
173
-
174
- @@bind_substitutions ||= Java::JavaUtil::HashMap.new
175
- unless bind_visitor = @@bind_substitutions.get(visitor)
176
- @@bind_substitutions.synchronized do
177
- unless @@bind_substitutions.get(visitor)
178
- bind_visitor = Class.new(visitor) do
179
- include ::Arel::Visitors::BindVisitor
180
- end
181
- @@bind_substitutions.put(visitor, bind_visitor)
182
- end
183
- end
184
- bind_visitor = @@bind_substitutions.get(visitor)
201
+ # DB specific types are detected but adapter specs (or extenders) are
202
+ # expected to hand tune these types for concrete databases.
203
+ # @return [Hash] the native database types
204
+ # @override
205
+ def native_database_types
206
+ @native_database_types ||= begin
207
+ types = @connection.native_database_types
208
+ modify_types(types)
209
+ types
185
210
  end
186
- bind_visitor
187
- end
188
-
189
- begin
190
- require 'arel/visitors/bind_visitor'
191
- rescue LoadError # AR-3.0
192
- def self.bind_substitution(visitor); visitor; end
193
- end
194
-
195
- def bind_substitution(visitor); self.class.bind_substitution(visitor); end
196
- private :bind_substitution
197
-
198
- # @override default implementation (does nothing silently)
211
+ end
212
+
213
+ # Allows for modification of the detected native types.
214
+ # @param types the resolved native database types
215
+ # @see #native_database_types
216
+ def modify_types(types)
217
+ types
218
+ end
219
+
220
+ # Abstract adapter default implementation does nothing silently.
221
+ # @override
199
222
  def structure_dump
200
223
  raise NotImplementedError, "structure_dump not supported"
201
224
  end
202
-
203
- def is_a?(klass) # :nodoc:
204
- # This is to fake out current_adapter? conditional logic in AR tests
205
- if Class === klass && klass.name =~ /#{adapter_name}Adapter$/i
206
- true
207
- else
208
- super
209
- end
210
- end
211
225
 
226
+ # JDBC adapters support migration.
227
+ # @return [true]
228
+ # @override
212
229
  def supports_migrations?
213
230
  true
214
231
  end
215
232
 
216
- def native_database_types # :nodoc:
217
- @connection.native_database_types
218
- end
219
-
220
- def database_name # :nodoc:
233
+ # Returns the underlying database name.
234
+ # @override
235
+ def database_name
221
236
  @connection.database_name
222
237
  end
223
238
 
239
+ # @private
224
240
  def native_sql_to_type(type)
225
241
  if /^(.*?)\(([0-9]+)\)/ =~ type
226
242
  tname, limit = $1, $2.to_i
@@ -232,7 +248,7 @@ module ActiveRecord
232
248
  if name == :primary_key
233
249
  next
234
250
  end
235
- if val[:name].downcase == tname.downcase &&
251
+ if val[:name].downcase == tname.downcase &&
236
252
  ( val[:limit].nil? || val[:limit].to_i == limit )
237
253
  return name, limit
238
254
  end
@@ -256,47 +272,147 @@ module ActiveRecord
256
272
  return nil, nil
257
273
  end
258
274
 
275
+ # @override
259
276
  def active?
260
277
  @connection.active?
261
278
  end
262
279
 
280
+ # @override
263
281
  def reconnect!
264
282
  @connection.reconnect! # handles adapter.configure_connection
265
283
  @connection
266
284
  end
267
285
 
286
+ # @override
268
287
  def disconnect!
269
288
  @connection.disconnect!
270
289
  end
271
290
 
272
291
  if ActiveRecord::VERSION::MAJOR < 3
273
-
274
- def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
275
- insert_sql(sql, name, pk, id_value, sequence_name, binds)
292
+
293
+ # @private
294
+ def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
295
+ insert_sql(sql, name, pk, id_value, sequence_name)
276
296
  end
277
297
  alias_chained_method :insert, :query_dirty, :jdbc_insert
278
-
279
- def jdbc_update(sql, name = nil, binds = []) # :nodoc:
298
+
299
+ # @private
300
+ def jdbc_update(sql, name = nil, binds = [])
280
301
  execute(sql, name, binds)
281
302
  end
282
303
  alias_chained_method :update, :query_dirty, :jdbc_update
283
-
284
- def jdbc_select_all(sql, name = nil, binds = []) # :nodoc:
304
+
305
+ # @private
306
+ def jdbc_select_all(sql, name = nil, binds = [])
285
307
  select(sql, name, binds)
286
308
  end
287
309
  alias_chained_method :select_all, :query_cache, :jdbc_select_all
288
-
310
+
311
+ end
312
+
313
+ # @note Used on AR 2.3 and 3.0
314
+ # @override
315
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
316
+ id = execute(sql, name)
317
+ id_value || id
289
318
  end
290
-
319
+
291
320
  def columns(table_name, name = nil)
292
321
  @connection.columns(table_name.to_s)
293
322
  end
294
-
295
- # Executes +sql+ statement in the context of this connection using
296
- # +binds+ as the bind substitutes. +name+ is logged along with
297
- # the executed +sql+ statement.
298
- def exec_query(sql, name = 'SQL', binds = []) # :nodoc:
299
- sql = to_sql(sql, binds)
323
+
324
+ # Starts a database transaction.
325
+ # @override
326
+ def begin_db_transaction
327
+ @connection.begin
328
+ end
329
+
330
+ # Commits the current database transaction.
331
+ # @override
332
+ def commit_db_transaction
333
+ @connection.commit
334
+ end
335
+
336
+ # Rolls back the current database transaction.
337
+ # @override
338
+ def rollback_db_transaction
339
+ @connection.rollback
340
+ end
341
+
342
+ # Starts a database transaction.
343
+ # @param isolation the transaction isolation to use
344
+ # @since 1.3.0
345
+ # @override on **AR-4.0**
346
+ def begin_isolated_db_transaction(isolation)
347
+ @connection.begin(isolation)
348
+ end
349
+
350
+ # Does this adapter support setting the isolation level for a transaction?
351
+ # Unlike 'plain' `ActiveRecord` we allow checking for concrete transaction
352
+ # isolation level support by the database.
353
+ # @param level optional to check if we support a specific isolation level
354
+ # @since 1.3.0
355
+ # @extension added optional level parameter
356
+ def supports_transaction_isolation?(level = nil)
357
+ @connection.supports_transaction_isolation?(level)
358
+ end
359
+
360
+ # Does our database (+ its JDBC driver) support save-points?
361
+ # @since 1.3.0
362
+ # @override
363
+ def supports_savepoints?
364
+ @connection.supports_savepoints?
365
+ end
366
+
367
+ # Creates a (transactional) save-point one can rollback to.
368
+ # Unlike 'plain' `ActiveRecord` it is allowed to pass a save-point name.
369
+ # @param name the save-point name
370
+ # @return save-point name (even if nil passed will be generated)
371
+ # @since 1.3.0
372
+ # @extension added optional name parameter
373
+ def create_savepoint(name = current_savepoint_name(true))
374
+ @connection.create_savepoint(name)
375
+ end
376
+
377
+ # Transaction rollback to a given (previously created) save-point.
378
+ # If no save-point name given rollback to the last created one.
379
+ # @param name the save-point name
380
+ # @since 1.3.0
381
+ # @extension added optional name parameter
382
+ def rollback_to_savepoint(name = current_savepoint_name)
383
+ @connection.rollback_savepoint(name)
384
+ end
385
+
386
+ # Release a previously created save-point.
387
+ # @note Save-points are auto-released with the transaction they're created
388
+ # in (on transaction commit or roll-back).
389
+ # @param name the save-point name
390
+ # @since 1.3.0
391
+ # @extension added optional name parameter
392
+ def release_savepoint(name = current_savepoint_name)
393
+ @connection.release_savepoint(name)
394
+ end
395
+
396
+ # Due tracking of save-points created in a LIFO manner, always returns
397
+ # the correct name if any (last) save-point has been marked and not released.
398
+ # Otherwise when creating a save-point same naming convention as
399
+ # `ActiveRecord` uses ("active_record_" prefix) will be returned.
400
+ # @return [String] the current save-point name
401
+ # @since 1.3.0
402
+ # @override
403
+ def current_savepoint_name(create = nil)
404
+ return "active_record_#{open_transactions}" if create
405
+ @connection.marked_savepoint_names.last || "active_record_#{open_transactions}"
406
+ end
407
+
408
+ # Executes a SQL query in the context of this connection using the bind
409
+ # substitutes.
410
+ # @param sql the query string (or AREL object)
411
+ # @param name logging marker for the executed SQL statement log entry
412
+ # @param binds the bind parameters
413
+ # @return [ActiveRecord::Result] or [Array] on **AR-2.3**
414
+ # @override available since **AR-3.1**
415
+ def exec_query(sql, name = 'SQL', binds = [])
300
416
  if prepared_statements?
301
417
  log(sql, name, binds) { @connection.execute_query(sql, binds) }
302
418
  else
@@ -305,35 +421,59 @@ module ActiveRecord
305
421
  end
306
422
  end
307
423
 
308
- # Executes insert +sql+ statement in the context of this connection using
309
- # +binds+ as the bind substitutes. +name+ is the logged along with
310
- # the executed +sql+ statement.
311
- def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
312
- sql = suble_binds to_sql(sql, binds), binds
313
- log(sql, name || 'SQL') { @connection.execute_insert(sql) }
424
+ # Executes an insert statement in the context of this connection.
425
+ # @param sql the query string (or AREL object)
426
+ # @param name logging marker for the executed SQL statement log entry
427
+ # @param binds the bind parameters
428
+ # @override available since **AR-3.1**
429
+ def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
430
+ if prepared_statements?
431
+ log(sql, name || 'SQL', binds) { @connection.execute_insert(sql, binds) }
432
+ else
433
+ sql = suble_binds sql, binds
434
+ log(sql, name || 'SQL') { @connection.execute_insert(sql) }
435
+ end
314
436
  end
315
437
 
316
- # Executes delete +sql+ statement in the context of this connection using
317
- # +binds+ as the bind substitutes. +name+ is the logged along with
318
- # the executed +sql+ statement.
319
- def exec_delete(sql, name, binds) # :nodoc:
320
- sql = suble_binds to_sql(sql, binds), binds
321
- log(sql, name || 'SQL') { @connection.execute_delete(sql) }
438
+ # Executes a delete statement in the context of this connection.
439
+ # @param sql the query string (or AREL object)
440
+ # @param name logging marker for the executed SQL statement log entry
441
+ # @param binds the bind parameters
442
+ # @override available since **AR-3.1**
443
+ def exec_delete(sql, name, binds)
444
+ if prepared_statements?
445
+ log(sql, name || 'SQL', binds) { @connection.execute_delete(sql, binds) }
446
+ else
447
+ sql = suble_binds sql, binds
448
+ log(sql, name || 'SQL') { @connection.execute_delete(sql) }
449
+ end
322
450
  end
323
451
 
324
- # Executes update +sql+ statement in the context of this connection using
325
- # +binds+ as the bind substitutes. +name+ is the logged along with
326
- # the executed +sql+ statement.
327
- def exec_update(sql, name, binds) # :nodoc:
328
- sql = suble_binds to_sql(sql, binds), binds
329
- log(sql, name || 'SQL') { @connection.execute_update(sql) }
452
+ # # Executes an update statement in the context of this connection.
453
+ # @param sql the query string (or AREL object)
454
+ # @param name logging marker for the executed SQL statement log entry
455
+ # @param binds the bind parameters
456
+ # @override available since **AR-3.1**
457
+ def exec_update(sql, name, binds)
458
+ if prepared_statements?
459
+ log(sql, name || 'SQL', binds) { @connection.execute_update(sql, binds) }
460
+ else
461
+ sql = suble_binds sql, binds
462
+ log(sql, name || 'SQL') { @connection.execute_update(sql) }
463
+ end
330
464
  end
331
-
465
+
332
466
  # Similar to {#exec_query} except it returns "raw" results in an array
333
- # where each rows is a hash with keys as columns (just like Rails used to
467
+ # where each rows is a hash with keys as columns (just like Rails used to
334
468
  # do up until 3.0) instead of wrapping them in a {#ActiveRecord::Result}.
335
- def exec_query_raw(sql, name = 'SQL', binds = [], &block) # :nodoc:
336
- sql = to_sql(sql, binds)
469
+ # @param sql the query string (or AREL object)
470
+ # @param name logging marker for the executed SQL statement log entry
471
+ # @param binds the bind parameters
472
+ # @yield [v1, v2] depending on the row values returned from the query
473
+ # In case a block is given it will yield each row from the result set
474
+ # instead of returning mapped query results in an array.
475
+ # @return [Array] unless a block is given
476
+ def exec_query_raw(sql, name = 'SQL', binds = [], &block)
337
477
  if prepared_statements?
338
478
  log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
339
479
  else
@@ -341,252 +481,321 @@ module ActiveRecord
341
481
  log(sql, name) { @connection.execute_query_raw(sql, &block) }
342
482
  end
343
483
  end
344
-
484
+
485
+ # @private
486
+ # @override
345
487
  def select_rows(sql, name = nil)
346
488
  exec_query_raw(sql, name).map!(&:values)
347
489
  end
348
-
490
+
349
491
  if ActiveRecord::VERSION::MAJOR > 3 # expects AR::Result e.g. from select_all
350
-
492
+
493
+ # @private
351
494
  def select(sql, name = nil, binds = [])
352
- exec_query(sql, name, binds)
495
+ exec_query(to_sql(sql, binds), name, binds)
353
496
  end
354
-
497
+
355
498
  else
356
-
499
+
500
+ # @private
357
501
  def select(sql, name = nil, binds = []) # NOTE: only (sql, name) on AR < 3.1
358
- exec_query_raw(sql, name, binds)
502
+ exec_query_raw(to_sql(sql, binds), name, binds)
359
503
  end
360
-
504
+
361
505
  end
362
-
363
- if ActiveRecord::VERSION::MAJOR < 3 # 2.3.x
364
-
365
- # NOTE: 2.3 log(sql, name) while does not like `name == nil`
366
-
506
+
367
507
  # Executes the SQL statement in the context of this connection.
368
- def execute(sql, name = nil, binds = [])
369
- sql = suble_binds to_sql(sql, binds), binds
508
+ # The return value from this method depends on the SQL type (whether
509
+ # it's a SELECT, INSERT etc.). For INSERTs a generated id might get
510
+ # returned while for UPDATE statements the affected row count.
511
+ # Please note that this method returns "raw" results (in an array) for
512
+ # statements that return a result set, while {#exec_query} is expected to
513
+ # return a `ActiveRecord::Result` (since AR 3.1).
514
+ # @note This method does not use prepared statements.
515
+ # @see #exec_query
516
+ # @see #exec_insert
517
+ # @see #exec_update
518
+ def execute(sql, name = nil, binds = nil)
519
+ sql = suble_binds to_sql(sql, binds), binds if binds
370
520
  if name == :skip_logging
371
521
  _execute(sql, name)
372
522
  else
373
- log(sql, name ||= 'SQL') { _execute(sql, name) }
523
+ log(sql, name) { _execute(sql, name) }
374
524
  end
375
525
  end
376
526
 
377
- else
378
- #elsif ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
379
-
380
- # NOTE: 3.0 log(sql, name) allow `name == nil` (handles `name ||= "SQL"`)
381
-
382
- # Executes the SQL statement in the context of this connection.
383
- def execute(sql, name = nil, binds = [])
384
- sql = suble_binds to_sql(sql, binds), binds
385
- if name == :skip_logging
527
+ # @private documented above
528
+ def execute(sql, name = nil, skip_logging = false)
529
+ if skip_logging.is_a?(Array)
530
+ binds, skip_logging = skip_logging, false
531
+ sql = suble_binds to_sql(sql, binds), binds
532
+ end
533
+ if skip_logging || name == :skip_logging
386
534
  _execute(sql, name)
387
535
  else
388
536
  log(sql, name) { _execute(sql, name) }
389
537
  end
390
- end
391
-
392
- # NOTE: 3.1 log(sql, name = "SQL", binds = []) `name == nil` is fine
393
- # TODO skip logging the binds (twice) until prepared-statement support
394
-
395
- #else
396
- end
397
-
398
- # we need to do it this way, to allow Rails stupid tests to always work
399
- # even if we define a new execute method. Instead of mixing in a new
400
- # execute, an _execute should be mixed in.
538
+ end if ActiveRecord::VERSION::MAJOR < 3 ||
539
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 )
540
+
541
+ # We need to do it this way, to allow Rails stupid tests to always work
542
+ # even if we define a new `execute` method. Instead of mixing in a new
543
+ # `execute`, an `_execute` should be mixed in.
544
+ # @deprecated it was only introduced due tests
545
+ # @private
401
546
  def _execute(sql, name = nil)
402
547
  @connection.execute(sql)
403
548
  end
404
549
  private :_execute
405
550
 
406
- # NOTE: we have an extra binds argument at the end due 2.3 support (due {#jdbc_insert}).
407
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
408
- id = execute(sql, name = nil, binds)
409
- id_value || id
410
- end
411
-
551
+ # @override
412
552
  def tables(name = nil)
413
553
  @connection.tables
414
554
  end
415
555
 
556
+ # @override
416
557
  def table_exists?(name)
417
558
  @connection.table_exists?(name) # schema_name = nil
418
559
  end
419
560
 
561
+ # @override
420
562
  def indexes(table_name, name = nil, schema_name = nil)
421
563
  @connection.indexes(table_name, name, schema_name)
422
564
  end
423
565
 
424
- def begin_db_transaction
425
- @connection.begin
566
+ # @override
567
+ def pk_and_sequence_for(table)
568
+ ( key = primary_key(table) ) ? [ key, nil ] : nil
426
569
  end
427
570
 
428
- def commit_db_transaction
429
- @connection.commit
571
+ # @override
572
+ def primary_key(table)
573
+ primary_keys(table).first
430
574
  end
431
575
 
432
- def rollback_db_transaction
433
- @connection.rollback
576
+ # @override
577
+ def primary_keys(table)
578
+ @connection.primary_keys(table)
434
579
  end
435
580
 
436
- def begin_isolated_db_transaction(isolation)
437
- @connection.begin(isolation)
438
- end
439
-
440
- # Does this adapter support setting the isolation level for a transaction?
441
- # @note We allow to ask for a specified transaction isolation level ...
442
- def supports_transaction_isolation?(level = nil)
443
- @connection.supports_transaction_isolation?(level)
444
- end
445
-
581
+ # @deprecated use {#update_lob_value} instead
446
582
  def write_large_object(*args)
447
583
  @connection.write_large_object(*args)
448
584
  end
449
585
 
450
- def pk_and_sequence_for(table)
451
- key = primary_key(table)
452
- [ key, nil ] if key
453
- end
454
-
455
- def primary_key(table)
456
- primary_keys(table).first
457
- end
458
-
459
- def primary_keys(table)
460
- @connection.primary_keys(table)
586
+ def update_lob_value(record, column, value)
587
+ @connection.update_lob_value(record, column, value)
461
588
  end
462
589
 
463
590
  if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
464
-
591
+
465
592
  #attr_reader :visitor unless method_defined?(:visitor) # not in 3.0
466
-
467
- # Converts an AREL AST to SQL.
468
- def to_sql(arel, binds = [])
593
+
594
+ # @private
595
+ def to_sql(arel, binds = nil)
469
596
  # NOTE: can not handle `visitor.accept(arel.ast)` right
470
597
  arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
471
598
  end
472
-
473
- elsif ActiveRecord::VERSION::MAJOR >= 3 # AR >= 3.1 or 4.0
474
-
475
- # Converts an AREL AST to SQL.
599
+
600
+ elsif ActiveRecord::VERSION::MAJOR < 3 # AR-2.3 'fake' #to_sql method
601
+
602
+ # @private
603
+ def to_sql(sql, binds = nil)
604
+ sql
605
+ end
606
+
607
+ else # AR >= 3.1 or 4.0
608
+
609
+ # @private
476
610
  def to_sql(arel, binds = [])
611
+ # NOTE: same on 3.1/3.2 but on 4.0 binds are dup-ed
612
+ # for us it is intentional to 'consume' (empty) the binds array
613
+ # due our {#suble_binds} hack (that will be getting deprecated)
477
614
  if arel.respond_to?(:ast)
478
- visitor.accept(arel.ast) { quote(*binds.shift.reverse) }
615
+ visitor.accept(arel.ast) do
616
+ quote(*binds.shift.reverse)
617
+ end
479
618
  else
480
619
  arel
481
620
  end
482
621
  end
483
-
484
- else # AR-2.3 no #to_sql method
485
-
486
- def to_sql(sql, binds = nil)
487
- sql
488
- end
489
-
622
+
490
623
  end
491
-
624
+
492
625
  protected
493
-
626
+
627
+ # @override so that we do not have to care having 2 arguments on 3.0
628
+ def log(sql, name = nil, binds = [])
629
+ unless binds.blank?
630
+ binds = binds.map do |column, value|
631
+ column ? [column.name, value] : [nil, value]
632
+ end
633
+ sql = "#{sql} #{binds.inspect}"
634
+ end
635
+ super(sql, name || 'SQL') # `log(sql, name)` on AR <= 3.0
636
+ end if ActiveRecord::VERSION::MAJOR < 3 ||
637
+ ( ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR < 1 )
638
+
494
639
  def translate_exception(e, message)
495
640
  # we shall not translate native "Java" exceptions as they might
496
641
  # swallow an ArJdbc / driver bug into a AR::StatementInvalid ...
497
642
  return e if e.is_a?(NativeException) # JRuby 1.6
498
643
  return e if e.is_a?(Java::JavaLang::Throwable)
499
- super # NOTE: wraps AR::JDBCError into AR::StatementInvalid, desired ?!
644
+
645
+ case e
646
+ when SystemExit, SignalException, NoMemoryError then e
647
+ # NOTE: wraps AR::JDBCError into AR::StatementInvalid, desired ?!
648
+ else super
649
+ end
500
650
  end
501
651
 
652
+ # Take an id from the result of an INSERT query.
653
+ # @return [Integer, NilClass]
502
654
  def last_inserted_id(result)
503
- result
655
+ if result.is_a?(Hash) || result.is_a?(ActiveRecord::Result)
656
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
657
+ else
658
+ result
659
+ end
504
660
  end
505
-
506
- # Helper to handle 3.x/4.0 uniformly override #table_definition as :
507
- #
661
+
662
+ # @private
663
+ def last_inserted_id(result)
664
+ if result.is_a?(Hash)
665
+ result.first.first[1] # .first = { "id"=>1 } .first = [ "id", 1 ]
666
+ else
667
+ result
668
+ end
669
+ end unless defined? ActiveRecord::Result
670
+
671
+ # Helper to easily override #table_definition (on AR 3.x/4.0) as :
672
+ # ```
508
673
  # def table_definition(*args)
509
674
  # new_table_definition(TableDefinition, *args)
510
675
  # end
511
- #
676
+ # ```
512
677
  def new_table_definition(table_definition, *args)
513
678
  table_definition.new(self) # args ignored only used for 4.0
514
679
  end
515
680
  private :new_table_definition
516
-
517
- # if adapter overrides #table_definition it works on 3.x as well as 4.0
681
+
682
+ # NOTE: make sure if adapter overrides #table_definition that it will
683
+ # work on AR 3.x as well as 4.0
518
684
  if ActiveRecord::VERSION::MAJOR > 3
519
-
685
+
520
686
  # aliasing #create_table_definition as #table_definition :
521
687
  alias table_definition create_table_definition
522
688
 
523
- # TableDefinition.new native_database_types, name, temporary, options
689
+ # `TableDefinition.new native_database_types, name, temporary, options`
690
+ # @private
524
691
  def create_table_definition(name, temporary, options)
525
692
  table_definition(name, temporary, options)
526
693
  end
527
-
528
- # arguments expected: (name, temporary, options)
694
+
695
+ # @note AR-4x arguments expected: `(name, temporary, options)`
696
+ # @private documented above
529
697
  def new_table_definition(table_definition, *args)
530
698
  table_definition.new native_database_types, *args
531
699
  end
532
700
  private :new_table_definition
533
-
701
+
534
702
  end
535
-
536
- private
537
-
703
+
704
+ # @return whether `:prepared_statements` are to be used
538
705
  def prepared_statements?
539
- self.class.prepared_statements?(config)
706
+ return @prepared_statements unless (@prepared_statements ||= nil).nil?
707
+ @prepared_statements = self.class.prepared_statements?(config)
540
708
  end
541
-
709
+
710
+ # Allows changing the prepared statements setting for this connection.
711
+ # @see #prepared_statements?
712
+ #def prepared_statements=(statements)
713
+ # @prepared_statements = statements
714
+ #end
715
+
716
+ private
717
+
542
718
  def self.prepared_statements?(config)
543
719
  config.key?(:prepared_statements) ?
544
720
  type_cast_config_to_boolean(config.fetch(:prepared_statements)) :
545
- false # NOTE: off by default for now
721
+ false # off by default
546
722
  end
547
723
 
548
724
  def suble_binds(sql, binds)
549
725
  return sql if binds.nil? || binds.empty?
550
726
  copy = binds.dup
727
+ # TODO deprecate/warn about this behavior !
551
728
  sql.gsub('?') { quote(*copy.shift.reverse) }
552
729
  end
553
-
554
- # @deprecated replaced with {#suble_binds}
730
+
731
+ # @deprecated Replaced with {#suble_binds}.
555
732
  def substitute_binds(sql, binds)
556
733
  suble_binds(extract_sql(sql), binds)
557
734
  end
558
735
 
559
- # @deprecated no longer used
736
+ # @deprecated No longer used, only kept for 1.2 API compatibility.
560
737
  def extract_sql(obj)
561
738
  obj.respond_to?(:to_sql) ? obj.send(:to_sql) : obj
562
739
  end
563
-
740
+
741
+ # Helper to get local/UTC time (based on `ActiveRecord::Base.default_timezone`).
742
+ def get_time(value)
743
+ get = ::ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
744
+ value.respond_to?(get) ? value.send(get) : value
745
+ end
746
+
564
747
  protected
565
-
748
+
749
+ # @return whether the given SQL string is a 'SELECT' like
750
+ # query (returning a result set)
566
751
  def self.select?(sql)
567
752
  JdbcConnection::select?(sql)
568
753
  end
569
754
 
755
+ # @return whether the given SQL string is an 'INSERT' query
570
756
  def self.insert?(sql)
571
757
  JdbcConnection::insert?(sql)
572
758
  end
573
759
 
760
+ # @return whether the given SQL string is an 'UPDATE' (or 'DELETE') query
574
761
  def self.update?(sql)
575
762
  ! select?(sql) && ! insert?(sql)
576
763
  end
577
-
764
+
578
765
  unless defined? AbstractAdapter.type_cast_config_to_integer
579
-
766
+
767
+ # @private
580
768
  def self.type_cast_config_to_integer(config)
581
769
  config =~ /\A\d+\z/ ? config.to_i : config
582
770
  end
583
771
 
772
+ # @private
584
773
  def self.type_cast_config_to_boolean(config)
585
774
  config == "false" ? false : config
586
775
  end
587
-
776
+
777
+ end
778
+
779
+ public
780
+
781
+ # @note Used by Java API to convert dates from (custom) SELECTs (might get refactored).
782
+ # @private
783
+ def _string_to_date(value)
784
+ jdbc_column_class.string_to_date(value)
588
785
  end
589
-
786
+
787
+ # @note Used by Java API to convert times from (custom) SELECTs (might get refactored).
788
+ # @private
789
+ def _string_to_time(value)
790
+ jdbc_column_class.string_to_dummy_time(value)
791
+ end
792
+
793
+ # @note Used by Java API to convert times from (custom) SELECTs (might get refactored).
794
+ # @private
795
+ def _string_to_timestamp(value)
796
+ jdbc_column_class.string_to_time(value)
797
+ end
798
+
590
799
  end
591
800
  end
592
801
  end